pax_global_header00006660000000000000000000000064150136527730014523gustar00rootroot0000000000000052 comment=2e64b4c12d3ecc9accedb066bd9b77f97e20be38 yara-4.5.3/000077500000000000000000000000001501365277300124705ustar00rootroot00000000000000yara-4.5.3/.clang-format000066400000000000000000000104221501365277300150420ustar00rootroot00000000000000# clang-format configuration applied to all source files in this project. # Requires clang-format version 10.0.0 or newer. --- Language: Cpp BasedOnStyle: Google AccessModifierOffset: -1 AlignAfterOpenBracket: AlwaysBreak AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignConsecutiveMacros: true AlignEscapedNewlines: Left AlignOperands: true AlignTrailingComments: true AllowAllArgumentsOnNextLine: true AllowAllConstructorInitializersOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: Inline AllowShortLambdasOnASingleLine: All AllowShortIfStatementsOnASingleLine: Never AllowShortLoopsOnASingleLine: true AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: Yes BinPackArguments: false BinPackParameters: false BraceWrapping: AfterCaseLabel: false AfterClass: false AfterControlStatement: true AfterEnum: false AfterFunction: true AfterNamespace: false AfterObjCDeclaration: false AfterStruct: true AfterUnion: false AfterExternBlock: false BeforeCatch: true BeforeElse: true IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true BreakBeforeBinaryOperators: None BreakBeforeBraces: Allman BreakBeforeInheritanceComma: false BreakInheritanceList: BeforeColon BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeColon BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true ColumnLimit: 80 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DerivePointerAlignment: true DisableFormat: false ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true IncludeBlocks: Preserve IncludeCategories: - Regex: '^' Priority: 2 - Regex: '^<.*\.h>' Priority: 1 - Regex: '^<.*' Priority: 2 - Regex: '.*' Priority: 3 IncludeIsMainRegex: '([-_](test|unittest))?$' IndentCaseLabels: false IndentPPDirectives: None IndentWidth: 2 IndentWrappedFunctionNames: false JavaScriptQuotes: Leave JavaScriptWrapImports: true KeepEmptyLinesAtTheStartOfBlocks: false MacroBlockBegin: "^\ begin_declarations|\ begin_struct.*$" MacroBlockEnd: "^\ end_declarations|\ end_struct.*$" MaxEmptyLinesToKeep: 1 NamespaceIndentation: None ObjCBinPackProtocolList: Never ObjCBlockIndentWidth: 2 ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: true PenaltyBreakAssignment: 100 PenaltyBreakBeforeFirstCallParameter: 1 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 PenaltyBreakString: 1000 PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 1000 PointerAlignment: Left RawStringFormats: - Language: Cpp Delimiters: - cc - CC - cpp - Cpp - CPP - 'c++' - 'C++' CanonicalDelimiter: '' BasedOnStyle: google - Language: TextProto Delimiters: - pb - PB - proto - PROTO EnclosingFunctions: - EqualsProto - EquivToProto - PARSE_PARTIAL_TEXT_PROTO - PARSE_TEST_PROTO - PARSE_TEXT_PROTO - ParseTextOrDie - ParseTextProtoOrDie CanonicalDelimiter: '' BasedOnStyle: google ReflowComments: true SortIncludes: true SortUsingDeclarations: true SpaceAfterCStyleCast: true SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true SpaceBeforeCpp11BracedList: false SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements SpaceBeforeRangeBasedForLoopColon: true SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 2 SpacesInAngles: false SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Auto StatementMacros: - Q_UNUSED - QT_REQUIRE_VERSION TabWidth: 8 UseTab: Never ... yara-4.5.3/.gitattributes000066400000000000000000000001761501365277300153670ustar00rootroot00000000000000# https://pete.akeo.ie/2010/12/that-darn-libtoolize-acconfigmacrodirm4.html *.sh text eol=lf *.ac text eol=lf *.am text eol=lfyara-4.5.3/.github/000077500000000000000000000000001501365277300140305ustar00rootroot00000000000000yara-4.5.3/.github/ISSUE_TEMPLATE/000077500000000000000000000000001501365277300162135ustar00rootroot00000000000000yara-4.5.3/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000010601501365277300207020ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve title: '' labels: bug assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Please complete the following information:** - OS: [e.g. iOS] - YARA version: [e.g. 4.3.0] **Additional context** Add any other context about the problem here. yara-4.5.3/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000011461501365277300217420ustar00rootroot00000000000000--- name: Feature request about: Suggest a new feature for this project title: '' labels: feature-request assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. yara-4.5.3/.github/workflows/000077500000000000000000000000001501365277300160655ustar00rootroot00000000000000yara-4.5.3/.github/workflows/build.yml000066400000000000000000000071101501365277300177060ustar00rootroot00000000000000name: Build and test on: [push, pull_request] env: UBSAN_OPTIONS: print_stacktrace=1 jobs: standard-build: runs-on: ubuntu-latest strategy: matrix: config: - "--enable-debug --enable-cuckoo --enable-magic --enable-macho --enable-pb-tests --enable-address-sanitizer --enable-undefined-behaviour-sanitizer" - "--enable-debug --enable-profiling --enable-cuckoo --enable-magic --enable-macho --enable-pb-tests --enable-address-sanitizer --enable-undefined-behaviour-sanitizer" steps: - uses: actions/checkout@v2 - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y \ autoconf \ automake \ gcc-multilib \ libtool \ libjansson-dev \ libmagic-dev \ libssl-dev \ protobuf-compiler \ protobuf-c-compiler \ libprotobuf-c-dev - name: Print versions run: | bison --version gcc --version - name: Prepare for building run: | ./bootstrap.sh ./configure ${{ matrix.config }} - name: Build run: make clean && make - name: Run tests run: make check - name: Print tests errors if: ${{ failure() }} run: cat test-suite.log mingw-build: runs-on: ubuntu-latest strategy: matrix: config: - "--host=x86_64-w64-mingw32" - "--host=i686-w64-mingw32" steps: - uses: actions/checkout@v2 - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y \ autoconf \ automake \ libtool \ libssl-dev \ gcc-mingw-w64 - name: Prepare for building run: | ./bootstrap.sh ./configure ${{ matrix.config }} - name: Build run: make clean && make macosx-build: runs-on: macos-13 steps: - uses: actions/checkout@v2 - name: Install dependencies run: | brew install \ autoconf \ automake \ bison \ flex \ libtool \ pkg-config \ jansson \ libmagic \ openssl@3 \ protobuf \ protobuf-c - name: Print versions run: | bison --version gcc --version - name: Prepare for building run: | ./bootstrap.sh ./configure --enable-debug --enable-cuckoo --enable-magic --enable-macho --enable-pb-tests - name: Build run: make clean && make - name: Run tests run: make check - name: Print tests errors if: ${{ failure() }} run: cat test-suite.log bigendian: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup multiarch/qemu-user-static run: | docker run --rm --privileged multiarch/qemu-user-static:register --reset - name: ubuntu-core:s390x-focal uses: docker://multiarch/ubuntu-core:s390x-focal with: args: > bash -c " apt-get update -y && DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get -y install tzdata && apt-get install -y automake libtool make gcc pkg-config bison git && cd /github/workspace && ./bootstrap.sh && ./configure --disable-proc-scan --enable-macho && make && make check && cat test-suite.log " yara-4.5.3/.github/workflows/coverity.yml000066400000000000000000000013021501365277300204500ustar00rootroot00000000000000name: Coverity on: push: branches: [master] jobs: coverity: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y \ autoconf \ automake \ gcc-multilib \ libtool \ libjansson-dev \ libmagic-dev \ libssl-dev - name: Prepare for building run: | ./bootstrap.sh ./configure - uses: vapier/coverity-scan-action@v1 with: project: 'plusvic/yara' email: ${{ secrets.COVERITY_SCAN_EMAIL }} token: ${{ secrets.COVERITY_SCAN_TOKEN }} yara-4.5.3/.github/workflows/oss-fuzz.yml000066400000000000000000000011271501365277300204110ustar00rootroot00000000000000name: CIFuzz on: [pull_request] jobs: Fuzzing: runs-on: ubuntu-latest steps: - name: Build Fuzzers uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master with: oss-fuzz-project-name: 'yara' dry-run: false - name: Run Fuzzers uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master with: oss-fuzz-project-name: 'yara' fuzz-seconds: 600 dry-run: false - name: Upload Crash uses: actions/upload-artifact@v4 if: failure() with: name: artifacts path: ./out/artifacts yara-4.5.3/.gitignore000066400000000000000000000017041501365277300144620ustar00rootroot00000000000000# Generic auto-generated build files *~ *.a *.gcda *.gcno *.gcov *.la *.lai *.lo *.Plo *.Po *.o *.so *.so.[0-9][0-9]* *.so.[0-9][0-9]*.[0-9][0-9]*.[0-9][0-9]* *.Tpo *.m4 *.dSYM .deps .libs INSTALL Makefile Makefile.in stamp-h1 # Specific auto-generated build files /ABOUT-NLS /aclocal.m4 /ar-lib /autom4te.cache/ /build-aux /compile /config.guess /config.h /config.h.in /config.log /config.rpath /config.status /config.sub /configure /depcomp /install-sh /libtool /ltmain.sh /missing /test-driver /ylwrap /m4 !/m4/acx_pthread.m4 # Project specific files /yara /yarac /libyara/modules/.dirstamp libyara/proc/.dirstamp /yara.pc /tests/.dirstamp # Linux and Mac files *.swp .DS_Store # Files generated by tests test-*[^.c] test-async test-magic test-rules.yarc # Bazel bazel-* # Visual Studio files Release/ Debug/ windows/*/.vs x64/ *.obj *.suo *.sdf *.opendb *.opensdf *.VC.db # NuGet windows/*/packages/ *.trs *.log .dirstamp .idea/ .vscode/ tests/mapper yara-4.5.3/.readthedocs.yaml000066400000000000000000000020041501365277300157130ustar00rootroot00000000000000# Read the Docs configuration file for Sphinx projects # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 # Set the OS, Python version and other tools you might need build: os: ubuntu-22.04 tools: python: "3.12" # You can also specify other tool versions: # nodejs: "20" # rust: "1.70" # golang: "1.20" # Build documentation in the "docs/" directory with Sphinx sphinx: configuration: docs/conf.py # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs # builder: "dirhtml" # Fail on all warnings to avoid broken references # fail_on_warning: true # Optionally build your docs in additional formats such as PDF and ePub # formats: # - pdf # - epub # Optional but recommended, declare the Python requirements required # to build your documentation # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html python: install: - requirements: docs/requirements.txt yara-4.5.3/AUTHORS000066400000000000000000000010711501365277300135370ustar00rootroot00000000000000# This is the official list of YARA authors for copyright purposes. # This file is distinct from the CONTRIBUTORS files. # See the latter for an explanation. # Names should be added to this file as # Name or Organization # The email address is not required for organizations. # Please keep the list sorted. Avast Google Inc. Hilko Bengen Joachim Metz Stefan Buehlmann Victor M. Alvarez ; Wesley Shields yara-4.5.3/CONTRIBUTORS000066400000000000000000000031321501365277300143470ustar00rootroot00000000000000# This is the official list of people who can contribute # (and typically have contributed) code to the YARA repository. # The AUTHORS file lists the copyright holders; this file # lists people. For example, Google employees are listed here # but not in AUTHORS, because Google holds the copyright. # # The submission process automatically checks to make sure # that people submitting code are listed in this file (by email address). # # Names should be added to this file only after verifying that # the individual or the individual's organization has agreed to # the appropriate Contributor License Agreement, found here: # # http://code.google.com/legal/individual-cla-v1.0.html # http://code.google.com/legal/corporate-cla-v1.0.html # # The agreement for individuals can be filled out on the web. # # When adding J Random Contributor's name to this file, # either J's name or J's organization's name should be # added to the AUTHORS file, depending on whether the # individual or corporate CLA was used. # Names should be added to this file like so: # Name # Please keep the list sorted. Anthony Desnos Antonio Vargas Gonzalez Christian Blichmann Hilko Bengen Joachim Metz Karel Hajek Karl Hiramoto Mike Wiacek Shane Huntley Stefan Buehlmann Victor M. Alvarez ; Wesley Shields yara-4.5.3/COPYING000066400000000000000000000027251501365277300135310ustar00rootroot00000000000000Copyright (c) 2007-2016. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. yara-4.5.3/Makefile.am000066400000000000000000000245371501365277300145370ustar00rootroot00000000000000# ABI_VERSION is passed to libtool as --version-number $(ABI_VERSION). This is # not related to YARA's release version, this is used for tracking changes in # the ABI, not in the project as a whole. # # The three number mean [current]:[revision]:[age], and they should updated as # follow: # # 1. With every release increment "revision". # # 2. If any interfaces have been added, removed, or changed since the last # update, increment "current" and set "revision" to 0. # # 3. If the changes in the interface were backward compatible (i.e: only adding # new APIs) increment "age", or set it to 0 if otherwise. # # See https://autotools.io/libtool/version.html for more details. # ABI_VERSION = 10:0:0 AM_CFLAGS=-Wall -D_GNU_SOURCE -I$(srcdir)/libyara/include # # When bison is used in POSIX yacc emulation mode (-y/--yacc option) it # produces warnings if we use Bison-specific features that are not supported # by yacc. With -Wno-yacc we turn off those warnings. Ideally we should call # bison without the -y/--yacc option, but autoconf insists on using bison in # yacc compatibility mode because of AC_PROG_YACC, and AC_PROG_BISON doesn't # exist. # AM_YFLAGS=-d -Wno-yacc if GCOV check: @tests/gcov-summary MOSTLYCLEANFILES = {cli,tests,libyara,libyara/proc,libyara/modules/*}/*.gc{no,da,ov} AM_CFLAGS+=-O0 -g -ftest-coverage -fprofile-arcs else if DEBUG AM_CFLAGS+=-g -fno-omit-frame-pointer endif if OPTIMIZATION AM_CFLAGS+=-O3 else AM_CFLAGS+=-O0 endif endif if ADDRESS_SANITIZER AM_CFLAGS+=-fsanitize=address endif if UB_SANITIZER AM_CFLAGS+=-fsanitize=undefined -fno-sanitize-recover=undefined endif if GCC AM_CFLAGS+=-fvisibility=hidden endif ACLOCAL_AMFLAGS=-I m4 # Rules for generating YARA modules from .proto files. For each .proto file # three files are generated: .c, .pb-c.c, and .pb-c.h. The .c file is generated # by protoc-gen-yara and the other two by protoc-gen-c. This is done only if # protoc is found, if not, files already in the repository are used instead # of generating fresh ones from the .proto file. # if PROTOC # SUFFIXES = .proto .pb-c.c .pb-c.h .c .proto.pb-c.c: $(PROTOC) --c_out=$(builddir) $^ -Ilibyara/pb/ -I=$(srcdir) .proto.pb-c.h: $(PROTOC) --c_out=$(builddir) $^ -Ilibyara/pb/ -I=$(srcdir) .proto.c: $(PROTOC) --c_out=$(builddir) $^ -Ilibyara/pb/ -I=$(srcdir) endif MODULES = libyara/modules/tests/tests.c MODULES += libyara/modules/elf/elf.c MODULES += libyara/modules/math/math.c MODULES += libyara/modules/time/time.c MODULES += libyara/modules/pe/pe.c MODULES += libyara/modules/pe/pe_utils.c MODULES += libyara/modules/console/console.c MODULES += libyara/modules/string/string.c if CUCKOO_MODULE MODULES += libyara/modules/cuckoo/cuckoo.c endif if MAGIC_MODULE MODULES += libyara/modules/magic/magic.c endif if HASH_MODULE MODULES += libyara/modules/hash/hash.c endif if DOTNET_MODULE MODULES += libyara/modules/dotnet/dotnet.c endif if MACHO_MODULE MODULES += libyara/modules/macho/macho.c endif if DEX_MODULE MODULES += libyara/modules/dex/dex.c endif if PB_TESTS_MODULE MODULES += libyara/modules/pb_tests/pb_tests.c MODULES += libyara/modules/pb_tests/pb_tests.pb-c.c endif if AUTHENTICODE_MODULE MODULES += libyara/modules/pe/authenticode-parser/authenticode.c MODULES += libyara/modules/pe/authenticode-parser/certificate.c MODULES += libyara/modules/pe/authenticode-parser/helper.c MODULES += libyara/modules/pe/authenticode-parser/countersignature.c MODULES += libyara/modules/pe/authenticode-parser/structs.c endif # # Add your modules here: # # MODULES += libyara/modules/yourmodule.c # include_HEADERS = libyara/include/yara.h yaraincludedir = $(includedir)/yara yarainclude_HEADERS = \ libyara/include/yara/ahocorasick.h \ libyara/include/yara/arena.h \ libyara/include/yara/atoms.h \ libyara/include/yara/base64.h \ libyara/include/yara/bitmask.h \ libyara/include/yara/compiler.h \ libyara/include/yara/error.h \ libyara/include/yara/exec.h \ libyara/include/yara/exefiles.h \ libyara/include/yara/filemap.h \ libyara/include/yara/hash.h \ libyara/include/yara/integers.h \ libyara/include/yara/libyara.h \ libyara/include/yara/limits.h \ libyara/include/yara/mem.h \ libyara/include/yara/modules.h \ libyara/include/yara/notebook.h \ libyara/include/yara/object.h \ libyara/include/yara/parser.h \ libyara/include/yara/proc.h \ libyara/include/yara/re.h \ libyara/include/yara/rules.h \ libyara/include/yara/scan.h \ libyara/include/yara/scanner.h \ libyara/include/yara/simple_str.h \ libyara/include/yara/sizedstr.h \ libyara/include/yara/stack.h \ libyara/include/yara/stopwatch.h \ libyara/include/yara/stream.h \ libyara/include/yara/strutils.h \ libyara/include/yara/threading.h \ libyara/include/yara/types.h \ libyara/include/yara/unaligned.h \ libyara/include/yara/utils.h noinst_HEADERS = \ libyara/crypto.h \ libyara/exception.h \ libyara/include/yara/dotnet.h \ libyara/include/yara/elf.h \ libyara/include/yara/endian.h \ libyara/include/yara/globals.h \ libyara/include/yara/hex_lexer.h \ libyara/include/yara/lexer.h \ libyara/include/yara/pe.h \ libyara/include/yara/pe_utils.h \ libyara/include/yara/re_lexer.h \ libyara/modules/module_list dist_noinst_DATA = libyara/pb/yara.proto lib_LTLIBRARIES = libyara.la libyara_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/libyara libyara_la_LDFLAGS = -version-number $(ABI_VERSION) BUILT_SOURCES = \ libyara/lexer.c \ libyara/hex_lexer.c \ libyara/re_lexer.c \ libyara/grammar.c libyara/grammar.h \ libyara/hex_grammar.c libyara/hex_grammar.h \ libyara/re_grammar.c libyara/re_grammar.h libyara_la_SOURCES = \ $(MODULES) \ libyara/grammar.y \ libyara/ahocorasick.c \ libyara/arena.c \ libyara/atoms.c \ libyara/base64.c \ libyara/bitmask.c \ libyara/compiler.c \ libyara/endian.c \ libyara/exec.c \ libyara/exefiles.c \ libyara/filemap.c \ libyara/hash.c \ libyara/hex_grammar.y \ libyara/hex_lexer.l \ libyara/lexer.l \ libyara/libyara.c \ libyara/mem.c \ libyara/modules.c \ libyara/notebook.c \ libyara/object.c \ libyara/parser.c \ libyara/proc.c \ libyara/re.c \ libyara/re_grammar.y \ libyara/re_lexer.l \ libyara/rules.c \ libyara/scan.c \ libyara/scanner.c \ libyara/simple_str.c \ libyara/sizedstr.c \ libyara/stack.c \ libyara/stopwatch.c \ libyara/strutils.c \ libyara/stream.c \ libyara/tlshc/tlsh.c \ libyara/tlshc/tlsh_impl.c \ libyara/tlshc/tlsh_util.c \ libyara/threading.c if USE_WINDOWS_PROC libyara_la_SOURCES += libyara/proc/windows.c endif if USE_LINUX_PROC libyara_la_SOURCES += libyara/proc/linux.c endif if USE_FREEBSD_PROC libyara_la_SOURCES += libyara/proc/freebsd.c endif if USE_OPENBSD_PROC libyara_la_SOURCES += libyara/proc/openbsd.c endif if USE_MACH_PROC libyara_la_SOURCES += libyara/proc/mach.c endif if USE_NO_PROC libyara_la_SOURCES += libyara/proc/none.c endif pkgconfigdir = $(libdir)/pkgconfig nodist_pkgconfig_DATA = yara.pc bin_PROGRAMS = yara yarac yara_SOURCES = \ cli/args.c \ cli/args.h \ cli/common.c \ cli/common.h \ cli/threading.c \ cli/threading.h \ cli/yara.c yara_LDADD = libyara.la yara_LDFLAGS = -static yarac_SOURCES = \ cli/args.c \ cli/args.h \ cli/common.c \ cli/common.h \ cli/yarac.c yarac_LDADD = libyara.la tests_mapper_SOURCES = tests/mapper.c tests_mapper_CFLAGS = -O0 test_alignment_SOURCES = tests/test-alignment.c tests/util.c test_alignment_LDADD = libyara.la test_alignment_LDFLAGS = -static test_arena_SOURCES = tests/test-arena.c tests/util.c test_arena_LDADD = libyara.la test_arena_LDFLAGS = -static test_atoms_SOURCES = tests/test-atoms.c tests/util.c test_atoms_LDADD = libyara.la test_atoms_LDFLAGS = -static test_rules_SOURCES = tests/test-rules.c tests/util.c test_rules_LDADD = libyara.la test_rules_LDFLAGS = -static if POSIX EXTRA_test_rules_DEPENDENCIES = tests/mapper$(EXEEXT) endif test_pe_SOURCES = tests/test-pe.c tests/util.c test_pe_LDADD = libyara.la test_pe_LDFLAGS = -static test_elf_SOURCES = tests/test-elf.c tests/util.c test_elf_LDADD = libyara.la test_elf_LDFLAGS = -static test_version_SOURCES = tests/test-version.c tests/util.c test_version_LDADD = libyara.la test_version_LDFLAGS = -static test_api_SOURCES = tests/test-api.c tests/util.c test_api_LDADD = libyara.la test_api_LDFLAGS = -static test_bitmask_SOURCES = tests/test-bitmask.c tests/util.c test_bitmask_LDADD = libyara.la test_bitmask_LDFLAGS = -static test_math_SOURCES = tests/test-math.c tests/util.c test_math_LDADD = libyara.la test_math_LDFLAGS = -static test_string_SOURCES = tests/test-string.c tests/util.c test_string_LDADD = libyara.la test_string_LDFLAGS = -static test_stack_SOURCES = tests/test-stack.c tests/util.c test_stack_LDADD = libyara.la test_stack_LDFLAGS = -static test_re_split_SOURCES = tests/test-re-split.c tests/util.c test_re_split_LDADD = libyara.la test_re_split_LDFLAGS = -static test_async_SOURCES = tests/test-async.c tests/util.c test_async_LDADD = libyara.la test_async_LDFLAGS = -static TESTS = $(check_PROGRAMS) TESTS_ENVIRONMENT = TOP_SRCDIR=$(top_srcdir) TOP_BUILDDIR=$(top_builddir) check_PROGRAMS = \ test-arena \ test-alignment \ test-atoms \ test-api \ test-rules \ test-pe \ test-elf \ test-version \ test-bitmask \ test-math \ test-stack \ test-re-split \ test-async \ test-string EXTRA_PROGRAMS = tests/mapper CLEANFILES = tests/mapper$(EXEEXT) if POSIX # The -fsanitize=address option makes test-exception fail. Include the test # only if the option is not enabled. if !ADDRESS_SANITIZER check_PROGRAMS+=test-exception test_exception_SOURCES = tests/test-exception.c tests/util.c test_exception_LDADD = libyara.la test_exception_LDFLAGS = -static endif endif if MACHO_MODULE check_PROGRAMS+=test-macho test_macho_SOURCES = tests/test-macho.c tests/util.c test_macho_LDADD = libyara.la test_macho_LDFLAGS = -static endif if DEX_MODULE check_PROGRAMS+=test-dex test_dex_SOURCES = tests/test-dex.c tests/util.c test_dex_LDADD = libyara.la test_dex_LDFLAGS = -static endif if DOTNET_MODULE check_PROGRAMS+=test-dotnet test_dotnet_SOURCES = tests/test-dotnet.c tests/util.c test_dotnet_LDADD = libyara.la test_dotnet_LDFLAGS = -static endif if MAGIC_MODULE check_PROGRAMS+=test-magic test_magic_SOURCES = tests/test-magic.c tests/util.c test_magic_LDADD = libyara.la test_magic_LDFLAGS = -static endif if PB_TESTS_MODULE check_PROGRAMS+=test-pb test_pb_SOURCES = tests/test-pb.c tests/util.c test_pb_LDADD = libyara.la test_pb_LDFLAGS = -static endif # man pages man1_MANS = yara.man yarac.man EXTRA_DIST = $(man1_MANS) README.md bootstrap.sh yara-4.5.3/README.md000066400000000000000000000152201501365277300137470ustar00rootroot00000000000000[![Join the chat at https://gitter.im/VirusTotal/yara](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/VirusTotal/yara?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![AppVeyor build status](https://ci.appveyor.com/api/projects/status/7glqg19w4oolm7pr?svg=true)](https://ci.appveyor.com/project/plusvic/yara) [![Coverity status](https://scan.coverity.com/projects/9057/badge.svg?flat=1)](https://scan.coverity.com/projects/plusvic-yara) ## YARA in a nutshell YARA is a tool aimed at (but not limited to) helping malware researchers to identify and classify malware samples. With YARA you can create descriptions of malware families (or whatever you want to describe) based on textual or binary patterns. Each description, a.k.a. rule, consists of a set of strings and a boolean expression which determine its logic. Let's see an example: ```yara rule silent_banker : banker { meta: description = "This is just an example" threat_level = 3 in_the_wild = true strings: $a = {6A 40 68 00 30 00 00 6A 14 8D 91} $b = {8D 4D B0 2B C1 83 C0 27 99 6A 4E 59 F7 F9} $c = "UVODFRYSIHLNWPEJXQZAKCBGMT" condition: $a or $b or $c } ``` The above rule is telling YARA that any file containing one of the three strings must be reported as *silent_banker*. This is just a simple example, more complex and powerful rules can be created by using wild-cards, case-insensitive strings, regular expressions, special operators and many other features that you'll find explained in [YARA's documentation](https://yara.readthedocs.org/). YARA is multi-platform, running on Windows, Linux and Mac OS X, and can be used through its command-line interface or from your own Python scripts with the yara-python extension. ## Additional resources Do you use GitHub for storing your YARA rules? [YARA-CI](https://yara-ci.cloud.virustotal.com) may be a useful addition to your toolbelt. This is GitHub application that provides continuous testing for your rules, helping you to identify common mistakes and false positives. If you plan to use YARA to scan compressed files (.zip, .tar, etc) you should take a look at [yextend](https://github.com/BayshoreNetworks/yextend), a very helpful extension to YARA developed and open-sourced by Bayshore Networks. Additionally, the guys from [InQuest](https://inquest.net/) have curated an awesome list of [YARA-related stuff](https://github.com/InQuest/awesome-yara). ## Who's using YARA * [0x101 Cyber Security](https://0x101-cyber-security.de) * [Adlice](https://www.adlice.com/) * [AlienVault](https://otx.alienvault.com/) * [Avast](https://www.avast.com/) * [BAE Systems](https://www.baesystems.com/home?r=ai) * [Bayshore Networks, Inc.](https://www.bayshorenetworks.com) * [Binalyze](https://www.binalyze.com/) * [BinaryAlert](https://github.com/airbnb/binaryalert) * [Blueliv](https://www.blueliv.com) * [Cado Security](https://docs.cadosecurity.com/cado-response/investigate/detections#setting-up-detections) * [Cisco Talos Intelligence Group](https://talosintelligence.com/) * [Cloudina Security](https://cloudina.co.uk) * [Cofense](https://cofense.com) * [Conix](https://www.conix.fr) * [Corelight](https://corelight.com/products/yara) * [CounterCraft](https://www.countercraft.eu) * [Cuckoo Sandbox](https://github.com/cuckoosandbox/cuckoo) * [Cyber Triage](https://www.cybertriage.com) * [Cybereason](https://www.cybereason.com) * [Digita Security](https://digitasecurity.com/product/uxprotect) * [Dragos Platform](https://dragos.com/platform/) * [Dtex Systems](https://dtexsystems.com) * [ESET](https://www.eset.com) * [ESTsecurity](https://www.estsecurity.com) * [Elastic Security](https://github.com/elastic/protections-artifacts) * [FactorX.ai](https://factorx.ai) * [Fidelis XPS](https://www.fidelissecurity.com/network-security-appliance/Fidelis-XPS) * [FireEye, Inc.](https://www.fireeye.com) * [Forcepoint](https://www.forcepoint.com) * [Fox-IT](https://www.fox-it.com) * [FSF](https://github.com/EmersonElectricCo/fsf) * [Guidance Software](https://www.guidancesoftware.com/endpointsecurity) * [Heroku](https://heroku.com) * [Hornetsecurity](https://www.hornetsecurity.com/en/) * [ICS Defense](https://icsdefense.net/) * [InQuest](https://www.inquest.net/) * [IntelOwl](https://github.com/intelowlproject/IntelOwl) * [Joe Security](https://www.joesecurity.org) * [Kaspersky Lab](https://www.kaspersky.com) * [KnowBe4](https://www.knowbe4.com) * [Koodous](https://koodous.com/) * [Laika BOSS](https://github.com/lmco/laikaboss) * [Lastline, Inc.](https://www.lastline.com) * [libguestfs](https://www.libguestfs.org/) * [LimaCharlie](https://limacharlie.io/) * [Malpedia](https://malpedia.caad.fkie.fraunhofer.de/) * [Malwation](https://malwation.com/) * [McAfee Advanced Threat Defense](https://mcafee.com/atd) * [Metaflows](https://www.metaflows.com) * [NBS System](https://www.nbs-system.com/) * [ndaal](https://ndaal.eu) * [NetLock](https://netlockendpoint.com) * [Nextron Systems](https://www.nextron-systems.com) * [Nozomi Networks](https://www.nozominetworks.com) * [osquery](https://www.osquery.io) * [Payload Security](https://www.payload-security.com) * [PhishMe](https://phishme.com/) * [Picus Security](https://www.picussecurity.com/) * [Radare2](https://rada.re) * [RedSocks Security](https://redsocks.eu/) * [ReversingLabs](https://reversinglabs.com) * [Scanii](https://scanii.com) * [SecondWrite](https://www.secondwrite.com) * [SonicWall](https://www.sonicwall.com/) * [SpamStopsHere](https://www.spamstopshere.com) * [Spyre](https://github.com/spyre-project/spyre) * [stoQ](https://stoq.punchcyber.com) * [Sublime Security](https://sublime.security) * [SumoLogic](https://sumologic.com) * [Tanium](https://www.tanium.com/) * [Tenable Network Security](https://www.tenable.com/) * [Tenzir](https://tenzir.com) * [The DigiTrust Group](https://www.digitrustgroup.com/) * [ThreatConnect](https://www.threatconnect.com/) * [ThreatStream, Inc.](https://www.threatstream.com) * [Thug](https://github.com/buffer/thug) * [Threat.Zone](https://threat.zone) * [TouchWeb](https://www.touchweb.fr) * [Trend Micro](https://www.trendmicro.com) * [UnpacMe](https://www.unpac.me) * [UpSight Security Inc.](https://upsight.ai/) * [Uptycs Inc](https://www.uptycs.com/) * [Veeam](https://www.veeam.com/) * [Verisys Antivirus API](https://www.ionxsolutions.com/products/verisys-virus-api) * [VirusTotal Intelligence](https://www.virustotal.com/intelligence/) * [VMRay](https://www.vmray.com/) * [Volexity](https://www.volexity.com/products-overview/volcano/) * [We Watch Your Website](https://www.wewatchyourwebsite.com/) * [x64dbg](https://x64dbg.com) * [YALIH](https://github.com/Masood-M/YALIH) Are you using it? Want to see your site listed here? yara-4.5.3/SECURITY.md000066400000000000000000000011341501365277300142600ustar00rootroot00000000000000Reporting security issues ========================= The YARA authors try their best to keep this software free of security issues, but 100% secure software does not exist. We appreciate all kinds of bug reports, but those that constitute a security vulnerability are specially welcomed and they will be prioritized and publicly acknowledged. Please do not open a GitHub issue to report a security vulnerability. If you believe you have found a security vulnerability, please submit your report to ``` vmalvarez@virustotal.com ``` We'll get back to you as soon as possible (usually in 1-2 days). yara-4.5.3/appveyor.yml000066400000000000000000000057001501365277300150620ustar00rootroot00000000000000# AppVeyor CI for Windows version: '{branch}-{build}' pull_requests: do_not_increment_build_number: true environment: matrix: - TARGET: vs2015 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 VisualStudioVersion: 14.0 platform: x86 configuration: Release artifact_postfix: win32 - TARGET: vs2015 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 VisualStudioVersion: 14.0 platform: x86 configuration: Debug - TARGET: vs2015 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 VisualStudioVersion: 14.0 platform: x64 configuration: Release artifact_postfix: win64 - TARGET: vs2015 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 VisualStudioVersion: 14.0 platform: x64 configuration: Debug - TARGET: cygwin for: - matrix: only: - TARGET: cygwin # Disable the installation of flex and bison packages. For some reason this # now (2021-04-19) upgrades the perl_base package to version 5.32.1-1 which # later fails with error: # Can't locate threads.pm in @INC (you may need to install the threads module) # # before_build: # - cmd: C:\cygwin64\setup-x86_64.exe --quiet-mode --no-desktop --no-shortcuts --no-startmenu --no-admin --packages flex,bison build_script: - cmd: C:\cygwin64\bin\bash -e -l -c "cd c:/projects/yara && ./build.sh" test_script: - cmd: C:\cygwin64\bin\bash -e -l -c "cd c:/projects/yara && make check" - matrix: only: - TARGET: vs2015 - configuration: Release before_build: - ps: nuget restore windows/vs2015/yara.sln build: project: windows/vs2015/yara.sln verbosity: minimal after_build: - cmd: 7z a yara-%APPVEYOR_BUILD_VERSION%-%ARTIFACT_POSTFIX%.zip %APPVEYOR_BUILD_FOLDER%\windows\%TARGET%\%CONFIGURATION%\yara*.exe artifacts: - path: yara-$(APPVEYOR_BUILD_VERSION)-$(ARTIFACT_POSTFIX).zip name: yara-$(APPVEYOR_BUILD_VERSION)-$(ARTIFACT_POSTFIX) type: zip deploy: tag: $(APPVEYOR_REPO_TAG_NAME) release: YARA $(APPVEYOR_REPO_TAG_NAME) provider: GitHub auth_token: secure: k+4xp4M/IEqXhKKYwo3DY2ko6VenOfSBEij3AasSiz1i8vsCwfcGxhuae0kj7Gj2 artifact: yara-$(APPVEYOR_BUILD_VERSION)-$(ARTIFACT_POSTFIX) draft: true on: APPVEYOR_REPO_TAG: true # deploy on tag push only test_script: - cmd: c:/projects/yara/windows/vs2015/%CONFIGURATION%/test-alignment.exe - matrix: only: - TARGET: vs2015 - configuration: Debug before_build: - ps: nuget restore windows/vs2015/yara.sln build: project: windows/vs2015/yara.sln verbosity: minimal test_script: - cmd: c:/projects/yara/windows/vs2015/%CONFIGURATION%/test-alignment.exe # Uncomment the lines below for enabling Remote Desktop in the Appveyor. This # allows connecting to the remote machine and debug issues. # on_finish: # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) yara-4.5.3/bootstrap.sh000077500000000000000000000000471501365277300150450ustar00rootroot00000000000000#!/bin/sh autoreconf --force --install yara-4.5.3/build.sh000077500000000000000000000000511501365277300141220ustar00rootroot00000000000000#!/bin/sh ./bootstrap.sh ./configure makeyara-4.5.3/cli/000077500000000000000000000000001501365277300132375ustar00rootroot00000000000000yara-4.5.3/cli/args.c000066400000000000000000000172371501365277300143510ustar00rootroot00000000000000/* Copyright (c) 2014-2021. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "args.h" #include "common.h" #include "unicode.h" #define args_is_long_arg(arg) (arg[0] == '-' && arg[1] == '-' && arg[2] != '\0') #define args_is_short_arg(arg) \ (arg[0] == '-' && arg[1] != '-' && arg[1] != '\0') args_option_t* args_get_short_option(args_option_t* options, const char_t opt) { while (options->type != ARGS_OPT_END) { if (opt == options->short_name) return options; options++; } return NULL; } args_option_t* args_get_long_option(args_option_t* options, const char_t* arg) { arg += 2; // skip starting -- while (options->type != ARGS_OPT_END) { if (options->long_name != NULL) { size_t l = _tcslen(options->long_name); if ((arg[l] == '\0' || arg[l] == '=') && _tcsstr(arg, options->long_name) == arg) { return options; } } options++; } return NULL; } args_error_type_t args_parse_option( args_option_t* opt, const char_t* opt_arg, int* opt_arg_was_used) { char_t* endptr = NULL; if (opt_arg_was_used != NULL) *opt_arg_was_used = 0; if (opt->count == opt->max_count) return ARGS_ERROR_TOO_MANY; switch (opt->type) { case ARGS_OPT_BOOLEAN: *(bool*) opt->value = !(*(bool*) opt->value); break; case ARGS_OPT_LONG: if (opt_arg == NULL) return ARGS_ERROR_REQUIRED_INTEGER_ARG; *(long*) opt->value = _tcstol(opt_arg, &endptr, 0); if (*endptr != '\0') return ARGS_ERROR_REQUIRED_INTEGER_ARG; if (opt_arg_was_used != NULL) *opt_arg_was_used = 1; break; case ARGS_OPT_LONG_LONG: if (opt_arg == NULL) return ARGS_ERROR_REQUIRED_INTEGER_ARG; *(long long*) opt->value = _tcstoll(opt_arg, &endptr, 0); if (*endptr != '\0') return ARGS_ERROR_REQUIRED_INTEGER_ARG; if (opt_arg_was_used != NULL) *opt_arg_was_used = 1; break; case ARGS_OPT_STRING: if (opt_arg == NULL) return ARGS_ERROR_REQUIRED_STRING_ARG; #ifdef _UNICODE if (opt->max_count > 1) ((const char**) opt->value)[opt->count] = unicode_to_ansi(opt_arg); else *(const char**) opt->value = unicode_to_ansi(opt_arg); #else if (opt->max_count > 1) ((const char**) opt->value)[opt->count] = opt_arg; else *(const char**) opt->value = opt_arg; #endif if (opt_arg_was_used != NULL) *opt_arg_was_used = 1; break; default: assert(0); } opt->count++; return ARGS_ERROR_OK; } void args_print_error(args_error_type_t error, const char_t* option) { switch (error) { case ARGS_ERROR_UNKNOWN_OPT: _ftprintf(stderr, _T("unknown option `%s`\n"), option); break; case ARGS_ERROR_TOO_MANY: _ftprintf(stderr, _T("too many `%s` options\n"), option); break; case ARGS_ERROR_REQUIRED_INTEGER_ARG: _ftprintf(stderr, _T("option `%s` requires an integer argument\n"), option); break; case ARGS_ERROR_REQUIRED_STRING_ARG: _ftprintf(stderr, _T("option `%s` requires a string argument\n"), option); break; case ARGS_ERROR_UNEXPECTED_ARG: _ftprintf(stderr, _T("option `%s` doesn't expect an argument\n"), option); break; default: return; } } int args_parse(args_option_t* options, int argc, const char_t** argv) { args_error_type_t error = ARGS_ERROR_OK; int i = 1; // start with i = 1, argv[0] is the program name int o = 0; while (i < argc) { const char_t* arg = argv[i]; if (args_is_long_arg(arg)) { args_option_t* opt = args_get_long_option(options, arg); if (opt != NULL) { const char_t* equal = _tcschr(arg, '='); if (equal) error = args_parse_option(opt, equal + 1, NULL); else error = args_parse_option(opt, NULL, NULL); } else { error = ARGS_ERROR_UNKNOWN_OPT; } } else if (args_is_short_arg(arg)) { for (int j = 1; arg[j] != '\0'; j++) { args_option_t* opt = args_get_short_option(options, arg[j]); if (opt != NULL) { if (arg[j + 1] == '\0') { int arg_used; // short option followed by a space, argv[i + 1] could be // an argument for the option (i.e: -a ) error = args_parse_option(opt, argv[i + 1], &arg_used); // argv[i + 1] was actually an argument to the option, skip it. if (arg_used) i++; } else { // short option followed by another option (i.e: -ab), no // argument for this option error = args_parse_option(opt, NULL, NULL); } } else { error = ARGS_ERROR_UNKNOWN_OPT; } if (error != ARGS_ERROR_OK) break; } } else { argv[o++] = arg; } if (error != ARGS_ERROR_OK) { args_print_error(error, arg); exit(1); } i++; } // Initialize to NULL the value pointers for all options. for (; options->type != ARGS_OPT_END; options++) options->value = NULL; return o; } void args_print_usage(args_option_t* options, int help_alignment) { char_t buffer[128]; for (; options->type != ARGS_OPT_END; options++) { int len = _stprintf(buffer, _T(" ")); if (options->short_name != '\0') len += _stprintf(buffer + len, _T("-%c"), options->short_name); else len += _stprintf(buffer + len, _T(" ")); if (options->short_name != '\0' && options->long_name != NULL) len += _stprintf(buffer + len, _T( ", ")); if (options->long_name != NULL) len += _stprintf(buffer + len, _T("--%s"), options->long_name); if (options->type == ARGS_OPT_STRING || options->type == ARGS_OPT_LONG || options->type == ARGS_OPT_LONG_LONG) { len += _stprintf( buffer + len, _T("%s%s"), (options->long_name != NULL) ? _T("=") : _T(" "), options->type_help); } _tprintf(_T("%-*s%s\n"), help_alignment, buffer, options->help); } } void args_free(args_option_t* options) { for (; options->type != ARGS_OPT_END; options++) { if (options->type == ARGS_OPT_STRING && options->value != NULL) { free(options->value); } } } yara-4.5.3/cli/args.h000066400000000000000000000071211501365277300143450ustar00rootroot00000000000000/* Copyright (c) 2014-2021. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ARGPARSE_H #define ARGPARSE_H #include #include "unicode.h" #ifdef __cplusplus extern "C" { #endif typedef enum _args_error_type { ARGS_ERROR_OK, ARGS_ERROR_UNKNOWN_OPT, ARGS_ERROR_TOO_MANY, ARGS_ERROR_REQUIRED_INTEGER_ARG, ARGS_ERROR_REQUIRED_STRING_ARG, ARGS_ERROR_UNEXPECTED_ARG, } args_error_type_t; typedef enum _args_option_type { // special ARGS_OPT_END, ARGS_OPT_GROUP, // options with no arguments ARGS_OPT_BOOLEAN, // options with arguments (optional or required) ARGS_OPT_LONG, ARGS_OPT_LONG_LONG, ARGS_OPT_STRING, } args_option_type_t; typedef struct _args_option { args_option_type_t type; const char_t short_name; const char_t *long_name; void *value; int max_count; const char_t *help; const char_t *type_help; int count; } args_option_t; #define OPT_BOOLEAN(short_name, long_name, value, ...) \ { \ ARGS_OPT_BOOLEAN, short_name, long_name, value, 1, __VA_ARGS__ \ } #define OPT_LONG(short_name, long_name, value, ...) \ { \ ARGS_OPT_LONG, short_name, long_name, value, 1, __VA_ARGS__ \ } #define OPT_LONG_LONG(short_name, long_name, value, ...) \ { \ ARGS_OPT_LONG_LONG, short_name, long_name, value, 1, __VA_ARGS__ \ } #define OPT_STRING_MULTI(short_name, long_name, value, max_count, ...) \ { \ ARGS_OPT_STRING, short_name, long_name, value, max_count, __VA_ARGS__ \ } #define OPT_STRING(short_name, long_name, value, ...) \ OPT_STRING_MULTI(short_name, long_name, value, 1, __VA_ARGS__) #define OPT_END() \ { \ ARGS_OPT_END, 0 \ } int args_parse(args_option_t *options, int argc, const char_t **argv); void args_print_usage(args_option_t *options, int alignment); void args_free(args_option_t *options); #ifdef __cplusplus } #endif #endif yara-4.5.3/cli/common.c000066400000000000000000000143661501365277300147050ustar00rootroot00000000000000/* Copyright (c) 2017-2021. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if defined(_WIN32) #include // In Visual C++ use _taccess_s, in MinGW use _access_s. #if defined(_MSC_VER) #define access _taccess_s #else #define access _access_s #endif #else // not _WIN32 #include #endif #include #include #include "common.h" #include "unicode.h" #define exit_with_code(code) \ { \ result = code; \ goto _exit; \ } #if defined(_UNICODE) char* unicode_to_ansi(const char_t* str) { if (str == NULL) return NULL; int str_len = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, str, -1, NULL, 0, NULL, NULL); char* str_utf8 = (char*) malloc(str_len); WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, str, -1, str_utf8, str_len, NULL, NULL); return str_utf8; } #endif bool compile_files(YR_COMPILER* compiler, int argc, const char_t** argv) { for (int i = 0; i < argc - 1; i++) { FILE* rule_file; const char_t* ns; const char_t* file_name; char_t* colon = NULL; int errors; if (access(argv[i], 0) != 0) { // A file with the name specified by the command-line argument wasn't // found, it may be because the name is prefixed with a namespace, so // lets try to find the colon that separates the namespace from the /// actual file name. colon = (char_t*) _tcschr(argv[i], ':'); } // The namespace delimiter must be a colon not followed by a backslash, // as :\ is the separator for a drive letter in Windows. if (colon && *(colon + 1) != '\\') { file_name = colon + 1; *colon = '\0'; ns = argv[i]; } else { file_name = argv[i]; ns = NULL; } if (_tcscmp(file_name, _T("-")) == 0) rule_file = stdin; else rule_file = _tfopen(file_name, _T("r")); if (rule_file == NULL) { _ftprintf(stderr, _T("error: could not open file: %s\n"), file_name); return false; } #if defined(_UNICODE) char* file_name_mb = unicode_to_ansi(file_name); char* ns_mb = unicode_to_ansi(ns); errors = yr_compiler_add_file(compiler, rule_file, ns_mb, file_name_mb); free(file_name_mb); free(ns_mb); #else errors = yr_compiler_add_file(compiler, rule_file, ns, file_name); #endif fclose(rule_file); if (errors > 0) return false; } return true; } int define_external_variables( char** ext_vars, YR_RULES* rules, YR_COMPILER* compiler) { int result = ERROR_SUCCESS; for (int i = 0; ext_vars[i] != NULL; i++) { char* equal_sign = strchr(ext_vars[i], '='); if (!equal_sign) { fprintf(stderr, "error: wrong syntax for `-d` option.\n"); return ERROR_SUCCESS; } // Replace the equal sign with null character to split the external // variable definition (i.e: myvar=somevalue) in two strings: identifier // and value. *equal_sign = '\0'; char* value = equal_sign + 1; char* identifier = ext_vars[i]; if (is_float(value)) { if (rules != NULL) result = yr_rules_define_float_variable(rules, identifier, atof(value)); if (compiler != NULL) result = yr_compiler_define_float_variable( compiler, identifier, atof(value)); } else if (is_integer(value)) { if (rules != NULL) result = yr_rules_define_integer_variable( rules, identifier, atoi(value)); if (compiler != NULL) result = yr_compiler_define_integer_variable( compiler, identifier, atoi(value)); } else if (strcmp(value, "true") == 0 || strcmp(value, "false") == 0) { if (rules != NULL) result = yr_rules_define_boolean_variable( rules, identifier, strcmp(value, "true") == 0); if (compiler != NULL) result = yr_compiler_define_boolean_variable( compiler, identifier, strcmp(value, "true") == 0); } else { if (rules != NULL) result = yr_rules_define_string_variable(rules, identifier, value); if (compiler != NULL) result = yr_compiler_define_string_variable( compiler, identifier, value); } } return result; } bool is_integer(const char* str) { if (*str == '-') str++; if (*str == '\0') return false; while (*str) { if (!isdigit(*str)) return false; str++; } return true; } bool is_float(const char* str) { bool has_dot = false; if (*str == '-') // skip the minus sign if present str++; if (*str == '.') // float can't start with a dot return false; while (*str) { if (*str == '.') { if (has_dot) // two dots, not a float return false; has_dot = true; } else if (!isdigit(*str)) { return false; } str++; } return has_dot; // to be float must contain a dot } yara-4.5.3/cli/common.h000066400000000000000000000035431501365277300147050ustar00rootroot00000000000000/* Copyright (c) 2017-2021. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef COMMON_H #define COMMON_H #include #include "unicode.h" #ifdef _UNICODE char* unicode_to_ansi(const char_t* str); #endif bool compile_files( YR_COMPILER* compiler, int argc, const char_t** argv); int define_external_variables( char** ext_vars, YR_RULES* rules, YR_COMPILER* compiler); bool is_integer(const char *str); bool is_float(const char *str); #endif yara-4.5.3/cli/threading.c000066400000000000000000000121311501365277300153460ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #if !defined(_WIN32) && !defined(__CYGWIN__) #include #include #include #endif #if defined(__APPLE__) #include #include #else #include #endif #include #include #include "threading.h" int cli_mutex_init(MUTEX* mutex) { #if defined(_WIN32) || defined(__CYGWIN__) InitializeCriticalSection(mutex); return 0; #else return pthread_mutex_init(mutex, NULL); #endif } void cli_mutex_destroy(MUTEX* mutex) { #if defined(_WIN32) || defined(__CYGWIN__) DeleteCriticalSection(mutex); #else pthread_mutex_destroy(mutex); #endif } void cli_mutex_lock(MUTEX* mutex) { #if defined(_WIN32) || defined(__CYGWIN__) EnterCriticalSection(mutex); #else pthread_mutex_lock(mutex); #endif } void cli_mutex_unlock(MUTEX* mutex) { #if defined(_WIN32) || defined(__CYGWIN__) LeaveCriticalSection(mutex); #else pthread_mutex_unlock(mutex); #endif } int cli_semaphore_init(SEMAPHORE* semaphore, int value) { #if defined(_WIN32) || defined(__CYGWIN__) *semaphore = CreateSemaphore(NULL, value, 65535, NULL); if (*semaphore == NULL) return GetLastError(); #elif defined(__APPLE__) int result = semaphore_create( mach_task_self(), semaphore, SYNC_POLICY_FIFO, value); if (result != KERN_SUCCESS) return result; #else *semaphore = malloc(sizeof(sem_t)); if (*semaphore == NULL) return errno; return sem_init(*semaphore, 0, value); #endif return 0; } void cli_semaphore_destroy(SEMAPHORE* semaphore) { #if defined(_WIN32) || defined(__CYGWIN__) CloseHandle(*semaphore); #elif defined(__APPLE__) semaphore_destroy(mach_task_self(), *semaphore); #else sem_destroy(*semaphore); free(*semaphore); #endif } /////////////////////////////////////////////////////////////////////////////// // Wait for the semaphore, but stop waiting when the current time exceeds the // given deadline. If deadline is in the past, exit immediately. // int cli_semaphore_wait(SEMAPHORE* semaphore, time_t deadline) { unsigned int timeout = (unsigned int) (deadline - time(NULL)); if (timeout <= 0) return ERROR_SCAN_TIMEOUT; #if defined(_WIN32) || defined(__CYGWIN__) if (WaitForSingleObject(*semaphore, timeout * 1000) == WAIT_TIMEOUT) return ERROR_SCAN_TIMEOUT; #elif defined(__APPLE__) mach_timespec_t ts; // semaphore_timedwait expects a timeout relative to the current time, not an // absolute timeout (deadline) as sem_timedwait does. ts.tv_sec = timeout; ts.tv_nsec = 0; if (semaphore_timedwait(*semaphore, ts) == KERN_OPERATION_TIMED_OUT) return ERROR_SCAN_TIMEOUT; #else struct timespec ts; // sem_timedwait expects an absolute timeout (deadline), not a relative // timeout as semaphore_timedwait does. ts.tv_sec = deadline; ts.tv_nsec = 0; if (sem_timedwait(*semaphore, &ts) == -1 && errno == ETIMEDOUT) return ERROR_SCAN_TIMEOUT; #endif return ERROR_SUCCESS; } void cli_semaphore_release(SEMAPHORE* semaphore) { #if defined(_WIN32) || defined(__CYGWIN__) ReleaseSemaphore(*semaphore, 1, NULL); #elif defined(__APPLE__) semaphore_signal(*semaphore); #else sem_post(*semaphore); #endif } int cli_create_thread( THREAD* thread, THREAD_START_ROUTINE start_routine, void* param) { #if defined(_WIN32) || defined(__CYGWIN__) *thread = CreateThread(NULL, 0, start_routine, param, 0, NULL); if (*thread == NULL) return GetLastError(); else return 0; #else return pthread_create(thread, NULL, start_routine, param); #endif } void cli_thread_join(THREAD* thread) { #if defined(_WIN32) || defined(__CYGWIN__) WaitForSingleObject(*thread, INFINITE); #else pthread_join(*thread, NULL); #endif } yara-4.5.3/cli/threading.h000066400000000000000000000051441501365277300153610ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef THREADING_H #define THREADING_H #if defined(_WIN32) || defined(__CYGWIN__) #include #else #include #include #if defined(__APPLE__) #include #else #include #endif #endif #if defined(_WIN32) || defined(__CYGWIN__) typedef HANDLE SEMAPHORE; typedef CRITICAL_SECTION MUTEX; typedef HANDLE THREAD; typedef LPTHREAD_START_ROUTINE THREAD_START_ROUTINE; #else typedef pthread_mutex_t MUTEX; typedef pthread_t THREAD; typedef void* (*THREAD_START_ROUTINE)(void*); #if defined(__APPLE__) typedef semaphore_t SEMAPHORE; #else typedef sem_t* SEMAPHORE; #endif #endif int cli_mutex_init(MUTEX* mutex); void cli_mutex_destroy(MUTEX* mutex); void cli_mutex_lock(MUTEX* mutex); void cli_mutex_unlock(MUTEX* mutex); int cli_semaphore_init(SEMAPHORE* semaphore, int value); void cli_semaphore_destroy(SEMAPHORE* semaphore); int cli_semaphore_wait(SEMAPHORE* semaphore, time_t abs_timeout); void cli_semaphore_release(SEMAPHORE* semaphore); int cli_create_thread( THREAD* thread, THREAD_START_ROUTINE start_routine, void* param); void cli_thread_join(THREAD* thread); #endif yara-4.5.3/cli/unicode.h000066400000000000000000000042711501365277300150420ustar00rootroot00000000000000/* Copyright (c) 2021. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_UNICODE_H #define YR_UNICODE_H #ifdef _MSC_VER #include #define char_t TCHAR #define PF_S "hs" #define PF_C "hc" #else #define char_t char #define _T(x) x #define PF_S "s" #define PF_C "c" #ifdef __CYGWIN__ #define _tcstok_s strtok_r #else #define _tcstok_s strtok_s #endif #define _tcscmp strcmp #define _tcsdup strdup #define _tcschr strchr #define _tcslen strlen #define _tcsstr strstr #define _tcstol strtol #define _tcstoll strtoll #define _tstoi atoi #define _tstof atof #define _tisdigit isdigit #define _tfopen fopen #define _ftprintf fprintf #define _stprintf sprintf #define _tprintf printf #define _tmain main #define _sntprintf snprintf #endif #endif yara-4.5.3/cli/yara.c000066400000000000000000001213161501365277300143430ustar00rootroot00000000000000/* Copyright (c) 2007-2021. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if !defined(_WIN32) && !defined(__CYGWIN__) // for getline(3) #define _POSIX_C_SOURCE 200809L #include #include #include #include #include #else #include #include #include #define PRIx64 "I64x" #define PRId64 "I64d" #endif #include #include #include #include #include #include #include "args.h" #include "common.h" #include "threading.h" #include "unicode.h" #define ERROR_COULD_NOT_CREATE_THREAD 100 #ifndef min #define min(x, y) ((x < y) ? (x) : (y)) #endif #define MAX_ARGS_TAG 32 #define MAX_ARGS_IDENTIFIER 32 #define MAX_ARGS_EXT_VAR 32 #define MAX_ARGS_MODULE_DATA 32 #define MAX_QUEUED_FILES 64 #define exit_with_code(code) \ { \ result = code; \ goto _exit; \ } typedef struct _MODULE_DATA { const char* module_name; YR_MAPPED_FILE mapped_file; struct _MODULE_DATA* next; } MODULE_DATA; typedef struct _CALLBACK_ARGS { const char_t* file_path; int current_count; } CALLBACK_ARGS; typedef struct _THREAD_ARGS { YR_SCANNER* scanner; CALLBACK_ARGS callback_args; time_t deadline; int current_count; } THREAD_ARGS; typedef struct _QUEUED_FILE { char_t* path; } QUEUED_FILE; typedef struct COMPILER_RESULTS { int errors; int warnings; } COMPILER_RESULTS; typedef struct SCAN_OPTIONS { bool follow_symlinks; bool recursive_search; time_t deadline; } SCAN_OPTIONS; #define MAX_ARGS_TAG 32 #define MAX_ARGS_IDENTIFIER 32 #define MAX_ARGS_EXT_VAR 32 #define MAX_ARGS_MODULE_DATA 32 static char* atom_quality_table; static char* tags[MAX_ARGS_TAG + 1]; static char* identifiers[MAX_ARGS_IDENTIFIER + 1]; static char* ext_vars[MAX_ARGS_EXT_VAR + 1]; static char* modules_data[MAX_ARGS_MODULE_DATA + 1]; static bool follow_symlinks = true; static bool recursive_search = false; static bool scan_list_search = false; static bool show_module_data = false; static bool show_tags = false; static bool show_stats = false; static bool show_strings = false; static bool show_string_length = false; static bool show_xor_key = false; static bool show_meta = false; static bool show_module_names = false; static bool show_namespace = false; static bool show_version = false; static bool show_help = false; static bool ignore_warnings = false; static bool fast_scan = false; static bool negate = false; static bool print_count_only = false; static bool strict_escape = false; static bool fail_on_warnings = false; static bool rules_are_compiled = false; static bool disable_console_logs = false; static long total_count = 0; static long limit = 0; static long timeout = 1000000; static long stack_size = DEFAULT_STACK_SIZE; static long threads = YR_MAX_THREADS; static long max_strings_per_rule = DEFAULT_MAX_STRINGS_PER_RULE; static long max_process_memory_chunk = DEFAULT_MAX_PROCESS_MEMORY_CHUNK; static long long skip_larger = 0; #define USAGE_STRING \ "Usage: yara [OPTION]... [NAMESPACE:]RULES_FILE... FILE | DIR | PID" args_option_t options[] = { OPT_STRING( 0, _T("atom-quality-table"), &atom_quality_table, _T("path to a file with the atom quality table"), _T("FILE")), OPT_BOOLEAN( 'C', _T("compiled-rules"), &rules_are_compiled, _T("load compiled rules")), OPT_BOOLEAN( 'c', _T("count"), &print_count_only, _T("print only number of matches")), OPT_BOOLEAN( 'E', _T("strict-escape"), &strict_escape, _T("warn on unknown escape sequences")), OPT_STRING_MULTI( 'd', _T("define"), &ext_vars, MAX_ARGS_EXT_VAR, _T("define external variable"), _T("VAR=VALUE")), OPT_BOOLEAN( 'q', _T("disable-console-logs"), &disable_console_logs, _T("disable printing console log messages")), OPT_BOOLEAN( 0, _T("fail-on-warnings"), &fail_on_warnings, _T("fail on warnings")), OPT_BOOLEAN('f', _T("fast-scan"), &fast_scan, _T("fast matching mode")), OPT_BOOLEAN('h', _T("help"), &show_help, _T("show this help and exit")), OPT_STRING_MULTI( 'i', _T("identifier"), &identifiers, MAX_ARGS_IDENTIFIER, _T("print only rules named IDENTIFIER"), _T("IDENTIFIER")), OPT_LONG( 0, _T("max-process-memory-chunk"), &max_process_memory_chunk, _T("set maximum chunk size while reading process memory") _T(" (default=1073741824)"), _T("NUMBER")), OPT_LONG( 'l', _T("max-rules"), &limit, _T("abort scanning after matching a NUMBER of rules"), _T("NUMBER")), OPT_LONG( 0, _T("max-strings-per-rule"), &max_strings_per_rule, _T("set maximum number of strings per rule (default=10000)"), _T("NUMBER")), OPT_STRING_MULTI( 'x', _T("module-data"), &modules_data, MAX_ARGS_MODULE_DATA, _T("pass FILE's content as extra data to MODULE"), _T("MODULE=FILE")), OPT_BOOLEAN( 'n', _T("negate"), &negate, _T("print only not satisfied rules (negate)"), NULL), OPT_BOOLEAN( 'N', _T("no-follow-symlinks"), &follow_symlinks, _T("do not follow symlinks when scanning")), OPT_BOOLEAN( 'w', _T("no-warnings"), &ignore_warnings, _T("disable warnings")), OPT_BOOLEAN('m', _T("print-meta"), &show_meta, _T("print metadata")), OPT_BOOLEAN( 'D', _T("print-module-data"), &show_module_data, _T("print module data")), OPT_BOOLEAN( 'M', _T("module-names"), &show_module_names, _T("show module names")), OPT_BOOLEAN( 'e', _T("print-namespace"), &show_namespace, _T("print rules' namespace")), OPT_BOOLEAN( 'S', _T("print-stats"), &show_stats, _T("print rules' statistics")), OPT_BOOLEAN( 's', _T("print-strings"), &show_strings, _T("print matching strings")), OPT_BOOLEAN( 'L', _T("print-string-length"), &show_string_length, _T("print length of matched strings")), OPT_BOOLEAN( 'X', _T("print-xor-key"), &show_xor_key, _T("print xor key and plaintext of matched strings")), OPT_BOOLEAN('g', _T("print-tags"), &show_tags, _T("print tags")), OPT_BOOLEAN( 'r', _T("recursive"), &recursive_search, _T("recursively search directories")), OPT_BOOLEAN( 0, _T("scan-list"), &scan_list_search, _T("scan files listed in FILE, one per line")), OPT_LONG_LONG( 'z', _T("skip-larger"), &skip_larger, _T("skip files larger than the given size when scanning a directory"), _T("NUMBER")), OPT_LONG( 'k', _T("stack-size"), &stack_size, _T("set maximum stack size (default=16384)"), _T("SLOTS")), OPT_STRING_MULTI( 't', _T("tag"), &tags, MAX_ARGS_TAG, _T("print only rules tagged as TAG"), _T("TAG")), OPT_LONG( 'p', _T("threads"), &threads, _T("use the specified NUMBER of threads to scan a directory"), _T("NUMBER")), OPT_LONG( 'a', _T("timeout"), &timeout, _T("abort scanning after the given number of SECONDS"), _T("SECONDS")), OPT_BOOLEAN( 'v', _T("version"), &show_version, _T("show version information")), OPT_END(), }; // file_queue is size-limited queue stored as a circular array, files are // removed from queue_head position and new files are added at queue_tail // position. The array has room for one extra element to avoid queue_head // being equal to queue_tail in a full queue. The only situation where // queue_head == queue_tail is when queue is empty. QUEUED_FILE file_queue[MAX_QUEUED_FILES + 1]; int queue_head; int queue_tail; SEMAPHORE used_slots; SEMAPHORE unused_slots; MUTEX queue_mutex; MUTEX output_mutex; MODULE_DATA* modules_data_list = NULL; static int file_queue_init() { int result; queue_tail = 0; queue_head = 0; result = cli_mutex_init(&queue_mutex); if (result != 0) return result; result = cli_semaphore_init(&used_slots, 0); if (result != 0) return result; return cli_semaphore_init(&unused_slots, MAX_QUEUED_FILES); } static void file_queue_destroy() { cli_mutex_destroy(&queue_mutex); cli_semaphore_destroy(&unused_slots); cli_semaphore_destroy(&used_slots); } static void file_queue_finish() { for (int i = 0; i < YR_MAX_THREADS; i++) cli_semaphore_release(&used_slots); } static int file_queue_put(const char_t* file_path, time_t deadline) { if (cli_semaphore_wait(&unused_slots, deadline) == ERROR_SCAN_TIMEOUT) return ERROR_SCAN_TIMEOUT; cli_mutex_lock(&queue_mutex); file_queue[queue_tail].path = _tcsdup(file_path); queue_tail = (queue_tail + 1) % (MAX_QUEUED_FILES + 1); cli_mutex_unlock(&queue_mutex); cli_semaphore_release(&used_slots); return ERROR_SUCCESS; } static char_t* file_queue_get(time_t deadline) { char_t* result; if (cli_semaphore_wait(&used_slots, deadline) == ERROR_SCAN_TIMEOUT) return NULL; cli_mutex_lock(&queue_mutex); if (queue_head == queue_tail) // queue is empty { result = NULL; } else { result = file_queue[queue_head].path; queue_head = (queue_head + 1) % (MAX_QUEUED_FILES + 1); } cli_mutex_unlock(&queue_mutex); cli_semaphore_release(&unused_slots); return result; } #if defined(_WIN32) || defined(__CYGWIN__) static bool is_directory(const char_t* path) { DWORD attributes = GetFileAttributes(path); if (attributes != INVALID_FILE_ATTRIBUTES && attributes & FILE_ATTRIBUTE_DIRECTORY) return true; else return false; } static int scan_dir(const char_t* dir, SCAN_OPTIONS* scan_opts) { int result = ERROR_SUCCESS; char_t path[YR_MAX_PATH]; _sntprintf(path, YR_MAX_PATH, _T("%s\\*"), dir); WIN32_FIND_DATA FindFileData; HANDLE hFind = FindFirstFile(path, &FindFileData); if (hFind != INVALID_HANDLE_VALUE) { do { _sntprintf(path, YR_MAX_PATH, _T("%s\\%s"), dir, FindFileData.cFileName); if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { LARGE_INTEGER file_size; file_size.HighPart = FindFileData.nFileSizeHigh; file_size.LowPart = FindFileData.nFileSizeLow; if (skip_larger > file_size.QuadPart || skip_larger <= 0) { result = file_queue_put(path, scan_opts->deadline); } else { _ftprintf( stderr, _T("skipping %s (%" PRIu64 " bytes) because it's larger than %lld bytes.\n"), path, file_size.QuadPart, skip_larger); } } else if ( scan_opts->recursive_search && _tcscmp(FindFileData.cFileName, _T(".")) != 0 && _tcscmp(FindFileData.cFileName, _T("..")) != 0) { result = scan_dir(path, scan_opts); } } while (result != ERROR_SCAN_TIMEOUT && FindNextFile(hFind, &FindFileData)); FindClose(hFind); } return result; } static int scan_file(YR_SCANNER* scanner, const char_t* filename) { YR_FILE_DESCRIPTOR fd = CreateFile( filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (fd == INVALID_HANDLE_VALUE) return ERROR_COULD_NOT_OPEN_FILE; int result = yr_scanner_scan_fd(scanner, fd); CloseHandle(fd); return result; } static int populate_scan_list(const char_t* filename, SCAN_OPTIONS* scan_opts) { char_t* context; DWORD nread; int result = ERROR_SUCCESS; HANDLE hFile = CreateFile( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { _ftprintf(stderr, _T("error: could not open file \"%s\".\n"), filename); return ERROR_COULD_NOT_OPEN_FILE; } DWORD fileSize = GetFileSize(hFile, NULL); if (fileSize == INVALID_FILE_SIZE) { _ftprintf( stderr, _T("error: could not determine size of file \"%s\".\n"), filename); CloseHandle(hFile); return ERROR_COULD_NOT_READ_FILE; } // INVALID_FILE_SIZE is 0xFFFFFFFF, so (+1) will not overflow char_t* buf = (char_t*) VirtualAlloc( NULL, fileSize + 1, MEM_COMMIT, PAGE_READWRITE); if (buf == NULL) { _ftprintf( stderr, _T("error: could not allocate memory for file \"%s\".\n"), filename); CloseHandle(hFile); return ERROR_INSUFFICIENT_MEMORY; } DWORD total = 0; while (total < fileSize) { if (!ReadFile(hFile, buf + total, fileSize - total, &nread, NULL)) { _ftprintf(stderr, _T("error: could not read file \"%s\".\n"), filename); CloseHandle(hFile); return ERROR_COULD_NOT_READ_FILE; } total += nread; } char_t* path = _tcstok_s(buf, _T("\n"), &context); while (result != ERROR_SCAN_TIMEOUT && path != NULL) { // Remove trailing carriage return, if present. if (*path != '\0') { char_t* final = path + _tcslen(path) - 1; if (*final == '\r') *final = '\0'; } if (is_directory(path)) result = scan_dir(path, scan_opts); else result = file_queue_put(path, scan_opts->deadline); path = _tcstok_s(NULL, _T("\n"), &context); } CloseHandle(hFile); return result; } #else static bool is_directory(const char* path) { struct stat st; if (stat(path, &st) == 0) return S_ISDIR(st.st_mode); return 0; } static int scan_dir(const char* dir, SCAN_OPTIONS* scan_opts) { int result = ERROR_SUCCESS; DIR* dp = opendir(dir); if (dp) { struct dirent* de = readdir(dp); char* full_path = calloc(YR_MAX_PATH, sizeof(char)); const size_t full_path_size = YR_MAX_PATH * sizeof(char); while (de && result != ERROR_SCAN_TIMEOUT) { struct stat st; snprintf(full_path, full_path_size, "%s/%s", dir, de->d_name); int err = lstat(full_path, &st); // If lstat returned error, or this directory entry is a symlink and the // user doesn't want to follow symlinks, skip the entry and continue with // the next one. if (err != 0 || (S_ISLNK(st.st_mode) && !scan_opts->follow_symlinks)) { de = readdir(dp); continue; } // If the directory entry is a symlink, check if it points to . or .. and // skip it in those cases. else if (S_ISLNK(st.st_mode)) { char buf[2]; int len = readlink(full_path, buf, sizeof(buf)); if ((len == 1 && buf[0] == '.') || (len == 2 && buf[0] == '.' && buf[1] == '.')) { de = readdir(dp); continue; } } err = stat(full_path, &st); if (err == 0) { if (S_ISREG(st.st_mode)) { if (skip_larger > st.st_size || skip_larger <= 0) { result = file_queue_put(full_path, scan_opts->deadline); } else { fprintf( stderr, "skipping %s (%" PRId64 " bytes) because it's larger than %lld" " bytes.\n", full_path, st.st_size, skip_larger); } } else if ( scan_opts->recursive_search && S_ISDIR(st.st_mode) && strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0) { result = scan_dir(full_path, scan_opts); } } de = readdir(dp); } free(full_path); closedir(dp); } return result; } static int scan_file(YR_SCANNER* scanner, const char_t* filename) { YR_FILE_DESCRIPTOR fd = open(filename, O_RDONLY); if (fd == -1) return ERROR_COULD_NOT_OPEN_FILE; int result = yr_scanner_scan_fd(scanner, fd); close(fd); return result; } static int populate_scan_list(const char* filename, SCAN_OPTIONS* scan_opts) { size_t nsize = 0; ssize_t nread; char* path = NULL; int result = ERROR_SUCCESS; FILE* fh_scan_list = fopen(filename, "r"); if (fh_scan_list == NULL) { fprintf(stderr, "error: could not open file \"%s\".\n", filename); return ERROR_COULD_NOT_OPEN_FILE; } while (result != ERROR_SCAN_TIMEOUT && (nread = getline(&path, &nsize, fh_scan_list)) != -1) { // remove trailing newline if (nread && path[nread - 1] == '\n') { path[nread - 1] = '\0'; nread--; } if (is_directory(path)) result = scan_dir(path, scan_opts); else result = file_queue_put(path, scan_opts->deadline); } free(path); fclose(fh_scan_list); return result; } #endif static void print_string(const uint8_t* data, int length, uint8_t xor_key) { for (int i = 0; i < length; i++) { uint8_t c = data[i] ^ xor_key; if (c >= 32 && c <= 126) _tprintf(_T("%c"), c); else _tprintf(_T("\\x%02X"), c); } } static char cescapes[] = { 0, 0, 0, 0, 0, 0, 0, 'a', 'b', 't', 'n', 'v', 'f', 'r', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static void print_escaped_data(const uint8_t* data, size_t length) { for (size_t i = 0; i < length; i++) { switch (data[i]) { case '\"': case '\'': case '\\': _tprintf(_T("\\%" PF_C), data[i]); break; default: if (data[i] >= 127) _tprintf(_T("\\%03o"), data[i]); else if (data[i] >= 32) _tprintf(_T("%" PF_C), data[i]); else if (cescapes[data[i]] != 0) _tprintf(_T("\\%" PF_C), cescapes[data[i]]); else _tprintf(_T("\\%03o"), data[i]); } } } void print_escaped_file_path(const char_t* str) { for (size_t i = 0; str[i] != '\0'; ++i) { if (str[i] == _T('\n')) { _tprintf(_T("\\n")); } else if (str[i] == _T('\r')) { _tprintf(_T("\\r")); } else { _tprintf(_T("%c"), str[i]); } } _tprintf(_T("\n")); } static void print_hex_string(const uint8_t* data, int length) { for (int i = 0; i < min(64, length); i++) _tprintf(_T("%s%02X"), (i == 0 ? _T("") : _T(" ")), data[i]); if (length > 64) _tprintf(_T(" ...")); } static void print_error(int error) { switch (error) { case ERROR_SUCCESS: break; case ERROR_COULD_NOT_ATTACH_TO_PROCESS: fprintf(stderr, "can not attach to process (try running as root)\n"); break; case ERROR_INSUFFICIENT_MEMORY: fprintf(stderr, "not enough memory\n"); break; case ERROR_SCAN_TIMEOUT: fprintf(stderr, "scanning timed out\n"); break; case ERROR_COULD_NOT_OPEN_FILE: fprintf(stderr, "could not open file\n"); break; case ERROR_UNSUPPORTED_FILE_VERSION: fprintf(stderr, "rules were compiled with a different version of YARA\n"); break; case ERROR_INVALID_FILE: fprintf(stderr, "invalid compiled rules file.\n"); break; case ERROR_CORRUPT_FILE: fprintf(stderr, "corrupt compiled rules file.\n"); break; case ERROR_EXEC_STACK_OVERFLOW: fprintf( stderr, "stack overflow while evaluating condition " "(see --stack-size argument) \n"); break; case ERROR_INVALID_EXTERNAL_VARIABLE_TYPE: fprintf(stderr, "invalid type for external variable\n"); break; case ERROR_TOO_MANY_MATCHES: fprintf(stderr, "too many matches\n"); break; default: fprintf(stderr, "error: %d\n", error); break; } } static void print_scanner_error(YR_SCANNER* scanner, int error) { YR_RULE* rule = yr_scanner_last_error_rule(scanner); YR_STRING* string = yr_scanner_last_error_string(scanner); if (rule != NULL && string != NULL) { fprintf( stderr, "string \"%s\" in rule \"%s\" caused ", string->identifier, rule->identifier); } else if (rule != NULL) { fprintf(stderr, "rule \"%s\" caused ", rule->identifier); } print_error(error); } static void print_compiler_error( int error_level, const char* file_name, int line_number, const YR_RULE* rule, const char* message, void* user_data) { char* msg_type; if (error_level == YARA_ERROR_LEVEL_ERROR) { msg_type = "error"; } else if (!ignore_warnings) { COMPILER_RESULTS* compiler_results = (COMPILER_RESULTS*) user_data; compiler_results->warnings++; msg_type = "warning"; } else { return; } if (rule != NULL) { fprintf( stderr, "%s: rule \"%s\" in %s(%d): %s\n", msg_type, rule->identifier, file_name, line_number, message); } else { fprintf( stderr, "%s(%d): %s: %s\n", file_name, line_number, msg_type, message); } } static void print_rules_stats(YR_RULES* rules) { YR_RULES_STATS stats; int t = sizeof(stats.top_ac_match_list_lengths) / sizeof(stats.top_ac_match_list_lengths[0]); int result = yr_rules_get_stats(rules, &stats); if (result != ERROR_SUCCESS) { print_error(result); return; } _tprintf( _T("size of AC transition table : %d\n"), stats.ac_tables_size); _tprintf( _T("average length of AC matches lists : %f\n"), stats.ac_average_match_list_length); _tprintf(_T("number of rules : %d\n"), stats.num_rules); _tprintf(_T("number of strings : %d\n"), stats.num_strings); _tprintf(_T("number of AC matches : %d\n"), stats.ac_matches); _tprintf( _T("number of AC matches in root node : %d\n"), stats.ac_root_match_list_length); _tprintf(_T("number of AC matches in top %d longest lists\n"), t); for (int i = 0; i < t; i++) _tprintf(_T(" %3d: %d\n"), i + 1, stats.top_ac_match_list_lengths[i]); _tprintf(_T("match list length percentiles\n")); for (int i = 100; i >= 0; i--) _tprintf(_T(" %3d: %d\n"), i, stats.ac_match_list_length_pctls[i]); } static int handle_message( YR_SCAN_CONTEXT* context, int message, YR_RULE* rule, void* data) { const char* tag; bool show = true; if (tags[0] != NULL) { // The user specified one or more -t arguments, let's show this rule // only if it's tagged with some of the specified tags. show = false; for (int i = 0; !show && tags[i] != NULL; i++) { yr_rule_tags_foreach(rule, tag) { if (strcmp(tag, tags[i]) == 0) { show = true; break; } } } } if (identifiers[0] != NULL) { // The user specified one or more -i arguments, let's show // this rule only if it's identifier is among of the provided ones. show = false; for (int i = 0; !show && identifiers[i] != NULL; i++) { if (strcmp(identifiers[i], rule->identifier) == 0) { show = true; break; } } } bool is_matching = (message == CALLBACK_MSG_RULE_MATCHING); show = show && ((!negate && is_matching) || (negate && !is_matching)); if (show && !print_count_only) { cli_mutex_lock(&output_mutex); if (show_namespace) _tprintf(_T("%" PF_S ":"), rule->ns->name); _tprintf(_T("%" PF_S " "), rule->identifier); if (show_tags) { _tprintf(_T("[")); yr_rule_tags_foreach(rule, tag) { // print a comma except for the first tag if (tag != rule->tags) _tprintf(_T(",")); _tprintf(_T("%" PF_S), tag); } _tprintf(_T("] ")); } // Show meta-data. if (show_meta) { YR_META* meta; _tprintf(_T("[")); yr_rule_metas_foreach(rule, meta) { if (meta != rule->metas) _tprintf(_T(",")); if (meta->type == META_TYPE_INTEGER) { _tprintf(_T("%" PF_S " =%" PRId64), meta->identifier, meta->integer); } else if (meta->type == META_TYPE_BOOLEAN) { _tprintf( _T("%" PF_S "=%" PF_S), meta->identifier, meta->integer ? "true" : "false"); } else { _tprintf(_T("%" PF_S "=\""), meta->identifier); print_escaped_data((uint8_t*) (meta->string), strlen(meta->string)); _tprintf(_T("\"")); } } _tprintf(_T("] ")); } print_escaped_file_path(((CALLBACK_ARGS*) data)->file_path); // Show matched strings. if (show_strings || show_string_length || show_xor_key) { YR_STRING* string; yr_rule_strings_foreach(rule, string) { YR_MATCH* match; yr_string_matches_foreach(context, string, match) { if (show_string_length) _tprintf( _T("0x%" PRIx64 ":%d:%" PF_S), match->base + match->offset, match->data_length, string->identifier); else _tprintf( _T("0x%" PRIx64 ":%" PF_S), match->base + match->offset, string->identifier); if (show_xor_key) { _tprintf(_T(":xor(0x%02x,"), match->xor_key); print_string(match->data, match->data_length, match->xor_key); _tprintf(_T(")")); } if (show_strings) { _tprintf(_T(": ")); if (STRING_IS_HEX(string)) print_hex_string(match->data, match->data_length); else print_string(match->data, match->data_length, 0); } _tprintf(_T("\n")); } } } cli_mutex_unlock(&output_mutex); } if (is_matching) { ((CALLBACK_ARGS*) data)->current_count++; total_count++; } if (limit != 0 && total_count >= limit) return CALLBACK_ABORT; return CALLBACK_CONTINUE; } static int callback( YR_SCAN_CONTEXT* context, int message, void* message_data, void* user_data) { YR_MODULE_IMPORT* mi; YR_STRING* string; YR_RULE* rule; YR_OBJECT* object; MODULE_DATA* module_data; switch (message) { case CALLBACK_MSG_RULE_MATCHING: case CALLBACK_MSG_RULE_NOT_MATCHING: return handle_message(context, message, (YR_RULE*) message_data, user_data); case CALLBACK_MSG_IMPORT_MODULE: mi = (YR_MODULE_IMPORT*) message_data; module_data = modules_data_list; while (module_data != NULL) { if (strcmp(module_data->module_name, mi->module_name) == 0) { mi->module_data = (void*) module_data->mapped_file.data; mi->module_data_size = module_data->mapped_file.size; break; } module_data = module_data->next; } return CALLBACK_CONTINUE; case CALLBACK_MSG_MODULE_IMPORTED: if (show_module_data) { object = (YR_OBJECT*) message_data; cli_mutex_lock(&output_mutex); #if defined(_WIN32) // In Windows restore stdout to normal text mode as yr_object_print_data // calls printf which is not supported in UTF-8 mode. // Explicitly flush the buffer before the switch in case we already // printed something and it haven't been flushed automatically. fflush(stdout); _setmode(_fileno(stdout), _O_TEXT); #endif yr_object_print_data(object, 0, 1); printf("\n"); #if defined(_WIN32) // Go back to UTF-8 mode. // Explicitly flush the buffer before the switch in case we already // printed something and it haven't been flushed automatically. fflush(stdout); _setmode(_fileno(stdout), _O_U8TEXT); #endif cli_mutex_unlock(&output_mutex); } return CALLBACK_CONTINUE; case CALLBACK_MSG_TOO_SLOW_SCANNING: if (ignore_warnings) return CALLBACK_CONTINUE; string = (YR_STRING*) message_data; rule = &context->rules->rules_table[string->rule_idx]; if (rule != NULL && string != NULL) fprintf( stderr, "warning: rule \"%s\": scanning with string %s is taking a very long " "time, it is either too general or very common.\n", rule->identifier, string->identifier); else return CALLBACK_CONTINUE; if (fail_on_warnings) return CALLBACK_ERROR; return CALLBACK_CONTINUE; case CALLBACK_MSG_TOO_MANY_MATCHES: if (ignore_warnings) return CALLBACK_CONTINUE; string = (YR_STRING*) message_data; rule = &context->rules->rules_table[string->rule_idx]; fprintf( stderr, "warning: rule \"%s\": too many matches for %s, results for this rule " "may be incorrect\n", rule->identifier, string->identifier); if (fail_on_warnings) return CALLBACK_ERROR; return CALLBACK_CONTINUE; case CALLBACK_MSG_CONSOLE_LOG: if (!disable_console_logs) _tprintf(_T("%" PF_S "\n"), (char*) message_data); return CALLBACK_CONTINUE; } return CALLBACK_ERROR; } #if defined(_WIN32) || defined(__CYGWIN__) static DWORD WINAPI scanning_thread(LPVOID param) #else static void* scanning_thread(void* param) #endif { int result = ERROR_SUCCESS; THREAD_ARGS* args = (THREAD_ARGS*) param; char_t* file_path = file_queue_get(args->deadline); while (file_path != NULL) { args->callback_args.current_count = 0; args->callback_args.file_path = file_path; time_t current_time = time(NULL); if (current_time < args->deadline) { yr_scanner_set_timeout( args->scanner, (int) (args->deadline - current_time)); result = scan_file(args->scanner, file_path); if (print_count_only) { cli_mutex_lock(&output_mutex); _tprintf(_T("%s: %d\n"), file_path, args->callback_args.current_count); cli_mutex_unlock(&output_mutex); } if (result != ERROR_SUCCESS) { cli_mutex_lock(&output_mutex); _ftprintf(stderr, _T("error scanning %s: "), file_path); print_scanner_error(args->scanner, result); cli_mutex_unlock(&output_mutex); } free(file_path); file_path = file_queue_get(args->deadline); } else { file_path = NULL; } } return 0; } static int load_modules_data() { for (int i = 0; modules_data[i] != NULL; i++) { char* equal_sign = strchr(modules_data[i], '='); if (!equal_sign) { fprintf(stderr, "error: wrong syntax for `-x` option.\n"); return false; } *equal_sign = '\0'; MODULE_DATA* module_data = (MODULE_DATA*) malloc(sizeof(MODULE_DATA)); if (module_data != NULL) { module_data->module_name = modules_data[i]; int result = yr_filemap_map(equal_sign + 1, &module_data->mapped_file); if (result != ERROR_SUCCESS) { free(module_data); fprintf(stderr, "error: could not open file \"%s\".\n", equal_sign + 1); return false; } module_data->next = modules_data_list; modules_data_list = module_data; } } return true; } static void unload_modules_data() { MODULE_DATA* module_data = modules_data_list; while (module_data != NULL) { MODULE_DATA* next_module_data = module_data->next; yr_filemap_unmap(&module_data->mapped_file); free(module_data); module_data = next_module_data; } modules_data_list = NULL; } int _tmain(int argc, const char_t** argv) { COMPILER_RESULTS cr; YR_COMPILER* compiler = NULL; YR_RULES* rules = NULL; YR_SCANNER* scanner = NULL; SCAN_OPTIONS scan_opts; bool arg_is_dir = false; int flags = 0; int result; argc = args_parse(options, argc, argv); scan_opts.follow_symlinks = follow_symlinks; scan_opts.recursive_search = recursive_search; if (show_version) { printf("%s\n", YR_VERSION); return EXIT_SUCCESS; } if (show_help) { printf( "YARA %s, the pattern matching swiss army knife.\n" "%s\n\n" "Mandatory arguments to long options are mandatory for " "short options too.\n\n", YR_VERSION, USAGE_STRING); args_print_usage(options, 43); printf( "\nSend bug reports and suggestions to: vmalvarez@virustotal.com.\n"); return EXIT_SUCCESS; } if (threads > YR_MAX_THREADS) { fprintf(stderr, "maximum number of threads is %d\n", YR_MAX_THREADS); return EXIT_FAILURE; } // This can be done before yr_initialize() because we aren't calling any // module functions, just accessing the name pointer for each module. if (show_module_names) { for (YR_MODULE* module = yr_modules_get_table(); module->name != NULL; module++) { printf("%s\n", module->name); } return EXIT_SUCCESS; } if (argc < 2) { // After parsing the command-line options we expect two additional // arguments, the rules file and the target file, directory or pid to // be scanned. fprintf(stderr, "yara: wrong number of arguments\n"); fprintf(stderr, "%s\n\n", USAGE_STRING); fprintf(stderr, "Try `--help` for more options\n"); return EXIT_FAILURE; } #if defined(_WIN32) && defined(_UNICODE) // In Windows set stdout to UTF-8 mode. if (_setmode(_fileno(stdout), _O_U8TEXT) == -1) { return EXIT_FAILURE; } #endif if (!load_modules_data()) exit_with_code(EXIT_FAILURE); result = yr_initialize(); if (result != ERROR_SUCCESS) { fprintf(stderr, "error: initialization error (%d)\n", result); exit_with_code(EXIT_FAILURE); } yr_set_configuration_uint32(YR_CONFIG_STACK_SIZE, (uint32_t) stack_size); yr_set_configuration_uint32( YR_CONFIG_MAX_STRINGS_PER_RULE, (uint32_t) max_strings_per_rule); yr_set_configuration_uint64( YR_CONFIG_MAX_PROCESS_MEMORY_CHUNK, max_process_memory_chunk); // Try to load the rules file as a binary file containing // compiled rules first if (rules_are_compiled) { // When a binary file containing compiled rules is provided, yara accepts // only two arguments, the compiled rules file and the target to be scanned. if (argc != 2) { fprintf( stderr, "error: can't accept multiple rules files if one of them is in " "compiled form.\n"); exit_with_code(EXIT_FAILURE); } // Not using yr_rules_load because it does not have support for unicode // file names. Instead use open _tfopen for openning the file and // yr_rules_load_stream for loading the rules from it. FILE* fh = _tfopen(argv[0], _T("rb")); if (fh != NULL) { YR_STREAM stream; stream.user_data = fh; stream.read = (YR_STREAM_READ_FUNC) fread; result = yr_rules_load_stream(&stream, &rules); fclose(fh); if (result == ERROR_SUCCESS) result = define_external_variables(ext_vars, rules, NULL); } else { result = ERROR_COULD_NOT_OPEN_FILE; } } else { // Rules file didn't contain compiled rules, let's handle it // as a text file containing rules in source form. if (yr_compiler_create(&compiler) != ERROR_SUCCESS) exit_with_code(EXIT_FAILURE); result = define_external_variables(ext_vars, NULL, compiler); if (result != ERROR_SUCCESS) { print_error(result); exit_with_code(EXIT_FAILURE); } if (atom_quality_table != NULL) { result = yr_compiler_load_atom_quality_table( compiler, atom_quality_table, 0); if (result != ERROR_SUCCESS) { fprintf(stderr, "error loading atom quality table: "); print_error(result); exit_with_code(EXIT_FAILURE); } } cr.errors = 0; cr.warnings = 0; yr_compiler_set_callback(compiler, print_compiler_error, &cr); if (strict_escape) compiler->strict_escape = true; else compiler->strict_escape = false; if (!compile_files(compiler, argc, argv)) exit_with_code(EXIT_FAILURE); if (cr.errors > 0) exit_with_code(EXIT_FAILURE); if (fail_on_warnings && cr.warnings > 0) exit_with_code(EXIT_FAILURE); result = yr_compiler_get_rules(compiler, &rules); yr_compiler_destroy(compiler); compiler = NULL; } if (result != ERROR_SUCCESS) { print_error(result); exit_with_code(EXIT_FAILURE); } if (show_stats) print_rules_stats(rules); cli_mutex_init(&output_mutex); if (fast_scan) flags |= SCAN_FLAGS_FAST_MODE; scan_opts.deadline = time(NULL) + timeout; arg_is_dir = is_directory(argv[argc - 1]); if (scan_list_search && arg_is_dir) { fprintf(stderr, "error: cannot use a directory as scan list.\n"); exit_with_code(EXIT_FAILURE); } else if (scan_list_search || arg_is_dir) { if (file_queue_init() != 0) { print_error(ERROR_INTERNAL_FATAL_ERROR); exit_with_code(EXIT_FAILURE); } THREAD thread[YR_MAX_THREADS]; THREAD_ARGS thread_args[YR_MAX_THREADS]; for (int i = 0; i < threads; i++) { thread_args[i].deadline = scan_opts.deadline; thread_args[i].current_count = 0; result = yr_scanner_create(rules, &thread_args[i].scanner); if (result != ERROR_SUCCESS) { print_error(result); exit_with_code(EXIT_FAILURE); } yr_scanner_set_callback( thread_args[i].scanner, callback, &thread_args[i].callback_args); yr_scanner_set_flags(thread_args[i].scanner, flags); if (cli_create_thread( &thread[i], scanning_thread, (void*) &thread_args[i])) { print_error(ERROR_COULD_NOT_CREATE_THREAD); exit_with_code(EXIT_FAILURE); } } if (arg_is_dir) { scan_dir(argv[argc - 1], &scan_opts); } else { result = populate_scan_list(argv[argc - 1], &scan_opts); } file_queue_finish(); // Wait for scan threads to finish for (int i = 0; i < threads; i++) cli_thread_join(&thread[i]); for (int i = 0; i < threads; i++) yr_scanner_destroy(thread_args[i].scanner); file_queue_destroy(); if (result != ERROR_SUCCESS) exit_with_code(EXIT_FAILURE); } else { CALLBACK_ARGS user_data = {argv[argc - 1], 0}; result = yr_scanner_create(rules, &scanner); if (result != ERROR_SUCCESS) { _ftprintf(stderr, _T("error: %d\n"), result); exit_with_code(EXIT_FAILURE); } yr_scanner_set_callback(scanner, callback, &user_data); yr_scanner_set_flags(scanner, flags); yr_scanner_set_timeout(scanner, timeout); // Assume the last argument is a file first. This assures we try to process // files that start with numbers first. result = scan_file(scanner, argv[argc - 1]); if (result == ERROR_COULD_NOT_OPEN_FILE) { // Is it a PID? To be a PID it must be made up entirely of digits. char_t* endptr = NULL; long pid = _tcstol(argv[argc - 1], &endptr, 10); if (pid > 0 && argv[argc - 1] != NULL && *endptr == '\x00') result = yr_scanner_scan_proc(scanner, (int) pid); } if (result != ERROR_SUCCESS) { _ftprintf(stderr, _T("error scanning %s: "), argv[argc - 1]); print_scanner_error(scanner, result); exit_with_code(EXIT_FAILURE); } if (print_count_only) _tprintf(_T("%d\n"), user_data.current_count); #ifdef YR_PROFILING_ENABLED yr_scanner_print_profiling_info(scanner); #endif } result = EXIT_SUCCESS; _exit: unload_modules_data(); if (scanner != NULL) yr_scanner_destroy(scanner); if (compiler != NULL) yr_compiler_destroy(compiler); if (rules != NULL) yr_rules_destroy(rules); yr_finalize(); args_free(options); return result; } yara-4.5.3/cli/yarac.c000066400000000000000000000155631501365277300145140ustar00rootroot00000000000000/* Copyright (c) 2013-2021. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _WIN32 #include #include #include #include #else #include #endif #include #include #include #include #include #include "args.h" #include "common.h" #define MAX_ARGS_EXT_VAR 32 #define exit_with_code(code) \ { \ result = code; \ goto _exit; \ } typedef struct COMPILER_RESULTS { int errors; int warnings; } COMPILER_RESULTS; static char* atom_quality_table; static char* ext_vars[MAX_ARGS_EXT_VAR + 1]; static bool ignore_warnings = false; static bool show_version = false; static bool show_help = false; static bool strict_escape = false; static bool fail_on_warnings = false; static long max_strings_per_rule = DEFAULT_MAX_STRINGS_PER_RULE; #define USAGE_STRING \ "Usage: yarac [OPTION]... [NAMESPACE:]SOURCE_FILE... OUTPUT_FILE" args_option_t options[] = { OPT_STRING( 0, _T("atom-quality-table"), &atom_quality_table, _T("path to a file with the atom quality table"), _T("FILE")), OPT_STRING_MULTI( 'd', _T("define"), &ext_vars, MAX_ARGS_EXT_VAR, _T("define external variable"), _T("VAR=VALUE")), OPT_BOOLEAN( 0, _T("fail-on-warnings"), &fail_on_warnings, _T("fail on warnings")), OPT_BOOLEAN('h', _T("help"), &show_help, _T("show this help and exit")), OPT_BOOLEAN( 'E', _T("strict-escape"), &strict_escape, _T("warn on unknown escape sequences")), OPT_LONG( 0, _T("max-strings-per-rule"), &max_strings_per_rule, _T("set maximum number of strings per rule (default=10000)"), _T("NUMBER")), OPT_BOOLEAN( 'w', _T("no-warnings"), &ignore_warnings, _T("disable warnings")), OPT_BOOLEAN( 'v', _T("version"), &show_version, _T("show version information")), OPT_END(), }; static void report_error( int error_level, const char* file_name, int line_number, const YR_RULE* rule, const char* message, void* user_data) { char* msg_type; if (error_level == YARA_ERROR_LEVEL_ERROR) { msg_type = "error"; } else if (!ignore_warnings) { COMPILER_RESULTS* compiler_results = (COMPILER_RESULTS*) user_data; compiler_results->warnings++; msg_type = "warning"; } else { return; } if (rule != NULL) { fprintf( stderr, "%s: rule \"%s\" in %s(%d): %s\n", msg_type, rule->identifier, file_name, line_number, message); } else { fprintf( stderr, "%s: %s(%d): %s\n", msg_type, file_name, line_number, message); } } int _tmain(int argc, const char_t** argv) { COMPILER_RESULTS cr; YR_COMPILER* compiler = NULL; YR_RULES* rules = NULL; int result; argc = args_parse(options, argc, argv); if (show_version) { printf("%s\n", YR_VERSION); return EXIT_SUCCESS; } if (show_help) { printf("%s\n\n", USAGE_STRING); args_print_usage(options, 40); printf("\nSend bug reports and suggestions to: vmalvarez@virustotal.com\n"); return EXIT_SUCCESS; } if (argc < 2) { fprintf(stderr, "yarac: wrong number of arguments\n"); fprintf(stderr, "%s\n\n", USAGE_STRING); fprintf(stderr, "Try `--help` for more options\n"); exit_with_code(EXIT_FAILURE); } if (yr_initialize() != ERROR_SUCCESS) exit_with_code(EXIT_FAILURE); if (yr_compiler_create(&compiler) != ERROR_SUCCESS) exit_with_code(EXIT_FAILURE); if (define_external_variables(ext_vars, NULL, compiler) != ERROR_SUCCESS) exit_with_code(EXIT_FAILURE); if (atom_quality_table != NULL) { result = yr_compiler_load_atom_quality_table( compiler, atom_quality_table, 0); if (result != ERROR_SUCCESS) { fprintf(stderr, "error loading atom quality table\n"); exit_with_code(EXIT_FAILURE); } } cr.errors = 0; cr.warnings = 0; yr_set_configuration_uint32( YR_CONFIG_MAX_STRINGS_PER_RULE, max_strings_per_rule); yr_compiler_set_callback(compiler, report_error, &cr); if (strict_escape) compiler->strict_escape = true; else compiler->strict_escape = false; if (!compile_files(compiler, argc, argv)) exit_with_code(EXIT_FAILURE); if (cr.errors > 0) exit_with_code(EXIT_FAILURE); if (fail_on_warnings && cr.warnings > 0) exit_with_code(EXIT_FAILURE); result = yr_compiler_get_rules(compiler, &rules); if (result != ERROR_SUCCESS) { fprintf(stderr, "error: %d\n", result); exit_with_code(EXIT_FAILURE); } // Not using yr_rules_save because it does not have support for unicode // file names. Instead use open _tfopen for openning the file and // yr_rules_save_stream for writing the rules to it. FILE* fh = _tfopen(argv[argc - 1], _T("wb")); if (fh != NULL) { YR_STREAM stream; stream.user_data = fh; stream.write = (YR_STREAM_WRITE_FUNC) fwrite; result = yr_rules_save_stream(rules, &stream); fclose(fh); } if (result != ERROR_SUCCESS) { fprintf(stderr, "error: %d\n", result); exit_with_code(EXIT_FAILURE); } result = EXIT_SUCCESS; _exit: if (compiler != NULL) yr_compiler_destroy(compiler); if (rules != NULL) yr_rules_destroy(rules); yr_finalize(); args_free(options); return result; } yara-4.5.3/configure.ac000066400000000000000000000340271501365277300147640ustar00rootroot00000000000000AC_INIT([yara], [4.5.2], [vmalvarez@virustotal.com]) AM_SILENT_RULES([yes]) AC_CONFIG_SRCDIR([cli/yara.c]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) AC_CONFIG_MACRO_DIR([m4]) # AC_PROG_CC sets CFLAGS to "-g -O2" if it wasn't previously set. Let's set # an empty CFLAGS. : ${CFLAGS=""} no_std_allocator="-fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free" # automake 1.12 seems to require AM_PROG_AR, but automake 1.11 doesn't # recognize it. m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) AC_PROG_CC AM_PROG_LEX AC_PROG_YACC # If the C compiler supports the keyword inline, do nothing. Otherwise define # inline to __inline__ or __inline if it accepts one of those, otherwise define # inline to be empty. AC_C_INLINE # Defines WORDS_BIGENDIAN if building in a big-endian host. AC_C_BIGENDIAN LT_INIT AC_CANONICAL_HOST case $host_alias in i?86-*-mingw*) CFLAGS="$CFLAGS -D__MINGW_USE_VC2005_COMPAT" ;; esac AC_ARG_ENABLE([proc-scan], [AS_HELP_STRING([--disable-proc-scan], [disable process scanning])], [if test x$enableval = xyes; then AC_MSG_ERROR([ ***************************************************************** Process scanning is enabled by default, remove --enable-proc-scan. ***************************************************************** ]) else proc_interface=none CFLAGS="$CFLAGS -DUSE_NO_PROC" fi], [case $host_os in darwin*) CFLAGS="$CFLAGS -I/opt/local/include" # Starting with Mac OS X 10.11 (El Capitan) the OpenSSL headers # are in /usr/local/opt/openssl/include CFLAGS="$CFLAGS -DUSE_MACH_PROC -I/usr/local/opt/openssl/include" LDFLAGS="$LDFLAGS -L/usr/local/opt/openssl/lib" posix=true proc_interface=mach jemalloc_prefix=je_ ;; mingw*|msys*|cygwin*) CFLAGS="$CFLAGS -DUSE_WINDOWS_PROC" proc_interface=windows jemalloc_prefix= ;; linux*|netbsd*|dragonfly*|kfreebsd*) CFLAGS="$CFLAGS -DUSE_LINUX_PROC" posix=true proc_interface=linux jemalloc_prefix= ;; freebsd*) CFLAGS="$CFLAGS -DUSE_FREEBSD_PROC" posix=true proc_interface=freebsd jemalloc_prefix= ;; openbsd*) CFLAGS="$CFLAGS -DUSE_OPENBSD_PROC" CFLAGS="$CFLAGS -I/usr/local/include -L/usr/local/lib" posix=true proc_interface=openbsd jemalloc_prefix= ;; *) CFLAGS="$CFLAGS -DUSE_NO_PROC" proc_interface=none jemalloc_prefix= ;; esac]) ACX_PTHREAD( [LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" CC="$PTHREAD_CC"], [AC_MSG_ERROR([pthread API support is required.])]) AC_CHECK_LIB(m, isnan) AC_CHECK_LIB(m, log2) AS_IF([test "ac_cv_lib_m_isnan" = yes || test "$ac_cv_lib_m_log2" = yes], [PC_LIBS_PRIVATE="$PC_LIBS_PRIVATE -lm"]) AC_CHECK_FUNCS([strlcpy strlcat memmem timegm _mkgmtime clock_gettime]) AC_CHECK_HEADERS([stdbool.h]) AC_ARG_ENABLE([debug], [AS_HELP_STRING([--enable-debug], [compiles with -g option])], [if test x$enableval = xyes; then debug=true fi]) AC_ARG_ENABLE([gcov], [AS_HELP_STRING([--enable-gcov], [compiles with -O0 -g -ftest-coverage -fprofile-arcs])], [if test x$enableval = xyes; then gcov=true fi]) AC_ARG_ENABLE([optimization], [AS_HELP_STRING([--disable-optimization], [disable compiler optimizations with -O0])], [if test x$enableval = xyes; then optimization=false fi], [optimization=true]) AC_ARG_ENABLE([address-sanitizer], [AS_HELP_STRING([--enable-address-sanitizer], [compiles with -fsanitize=address])], [if test x$enableval = xyes; then address_sanitizer=true fi]) AC_ARG_ENABLE([undefined-behaviour-sanitizer], [AS_HELP_STRING([--enable-undefined-behaviour-sanitizer], [compiles with -fsanitize=undefined])], [if test x$enableval = xyes; then undefined_behaviour_sanitizer=true fi]) AC_ARG_ENABLE([profiling], [AS_HELP_STRING([--enable-profiling], [enable rules profiling support])], [if test x$enableval = xyes; then profiling_enabled=true CFLAGS="$CFLAGS -DYR_PROFILING_ENABLED" fi]) AC_ARG_WITH([debug-verbose], [AS_HELP_STRING([--with-debug-verbose=[[NUM]]], [Turn on runtime debugging information])], [if test $withval -gt 0; then AC_DEFINE_UNQUOTED([YR_DEBUG_VERBOSITY], [$withval]) else AC_MSG_ERROR([debug verbosity must be greater than 0]) fi]) AC_ARG_ENABLE([cuckoo], [AS_HELP_STRING([--enable-cuckoo], [enable cuckoo module])], [if test x$enableval = xyes; then build_cuckoo_module=true AC_CHECK_HEADERS([jansson.h],, AC_MSG_ERROR([please install Jansson library])) AC_CHECK_LIB(jansson, json_loadb,, AC_MSG_ERROR([please install Jansson library])) CFLAGS="$CFLAGS -DCUCKOO_MODULE" PC_REQUIRES_PRIVATE="$PC_REQUIRES_PRIVATE jansson" fi]) AC_ARG_ENABLE([magic], [AS_HELP_STRING([--enable-magic], [enable magic module])], [if test x$enableval = xyes; then build_magic_module=true AC_CHECK_HEADERS([magic.h],, AC_MSG_ERROR([please install libmagic library])) AC_CHECK_LIB(magic, magic_open,, AC_MSG_ERROR([please install libmagic library])) CFLAGS="$CFLAGS -DMAGIC_MODULE" PC_LIBS_PRIVATE="$PC_LIBS_PRIVATE -lmagic" fi]) AC_ARG_ENABLE([macho], [AS_HELP_STRING([--enable-macho], [enable macho module])], [if test x$enableval = xyes; then build_macho_module=true CFLAGS="$CFLAGS -DMACHO_MODULE" fi]) AC_ARG_ENABLE([dex], [AS_HELP_STRING([--enable-dex], [enable dex module])], [if test x$enableval = xyes; then build_dex_module=true CFLAGS="$CFLAGS -DDEX_MODULE" fi]) AC_ARG_ENABLE([debug-dex], [AS_HELP_STRING([--enable-debug-dex], [enable dex module debugging])], [if test x$enableval = xyes; then debug_dex_module=true CFLAGS="$CFLAGS -DDEBUG_DEX_MODULE" fi]) AC_ARG_ENABLE([pb-tests], [AS_HELP_STRING([--enable-pb-tests], [enable protobuf test module])], [if test x$enableval = xyes; then build_pb_tests_module=true AC_CHECK_PROG(PROTOC, protoc, protoc) AS_IF([test "x${PROTOC}" == "x"], [AC_MSG_ERROR([protobuf compiler "protoc" not found])]) # AC_CHECK_PROG(PROTOC_GEN_YARA, protoc-gen-yara, protoc-gen-yara) # AS_IF([test "x${PROTOC_GEN_YARA}" == "x"], # [AC_MSG_ERROR([please install https://github.com/VirusTotal/protoc-gen-yara])]) PKG_CHECK_MODULES([PROTOBUF_C], [libprotobuf-c >= 1.0.0]) AC_CHECK_LIB([protobuf-c], protobuf_c_message_unpack,, AC_MSG_ERROR([please install libprotobuf-c library])) CFLAGS="$CFLAGS -DPB_TESTS_MODULE" PC_REQUIRES_PRIVATE="$PC_REQUIRES_PRIVATE libprotobuf-c" fi]) # "dotnet" module is enabled by default. It can be disabled with --disable-dotnet. AC_ARG_ENABLE([dotnet], [AS_HELP_STRING([--disable-dotnet], [disable dotnet module])], [if test x$enableval = xyes; then AC_MSG_WARN([ ***************************************************************** The dotnet module is enabled by default now. No need to specify --enable-dotnet. To disable this module please use --disable-dotnet. ***************************************************************** ]) build_dotnet_module=true CFLAGS="$CFLAGS -DDOTNET_MODULE" else build_dotnet_module=false fi], [ build_dotnet_module=true CFLAGS="$CFLAGS -DDOTNET_MODULE" ] ) AC_ARG_WITH([jemalloc], [AS_HELP_STRING([--with-jemalloc], [use jemalloc to debug heap-related issues])], [if test x$withval = xyes; then mallctl=mallctl malloc_stats_print=malloc_stats_print AC_CHECK_LIB(jemalloc, $jemalloc_prefix$mallctl,, AC_MSG_ERROR([please install jemalloc library])) CFLAGS="$CFLAGS -DJEMALLOC -Dmallctl=$jemalloc_prefix$mallctl -Dmalloc_stats_print=$jemalloc_prefix$malloc_stats_print $no_std_allocator" PC_REQUIRES_PRIVATE="$PC_REQUIRES_PRIVATE jemalloc" fi]) AC_ARG_WITH([tcmalloc], [AS_HELP_STRING([--with-tcmalloc], [use tcmalloc as the default heap allocator])], [if test x$withval = xyes; then if test "x$with_jemalloc" = "xyes"; then AC_MSG_ERROR([Cannot compile with both tcmalloc and jemalloc]) fi AC_CHECK_LIB(tcmalloc, tc_cfree,, AC_MSG_ERROR([please install https://github.com/gperftools/gperftools])) CFLAGS="$CFLAGS -DTCMALLOC $no_std_allocator" PC_REQUIRES_PRIVATE="$PC_REQUIRES_PRIVATE tcmalloc" fi]) AC_ARG_WITH([mimalloc], [AS_HELP_STRING([--with-mimalloc], [use mimalloc as the default heap allocator])], [if test x$withval = xyes; then if test "x$with_jemalloc" = "xyes"; then AC_MSG_ERROR([Cannot compile with both mimalloc and jemalloc]) fi if test "x$with_tcmalloc" = "xyes"; then AC_MSG_ERROR([Cannot compile with both mimalloc and tcmalloc]) fi mi_malloc=mi_malloc AC_CHECK_LIB(mimalloc, $mi_malloc,, AC_MSG_ERROR([please install https://github.com/microsoft/mimalloc])) CFLAGS="$CFLAGS -DMIMALLOC $no_std_allocator" PC_REQUIRES_PRIVATE="$PC_REQUIRES_PRIVATE mimalloc" fi]) AC_ARG_WITH([cpu-profiler], [AS_HELP_STRING([--with-cpu-profiler], [compile with CPU profiling support])], [if test x$withval = xyes; then AC_CHECK_LIB(profiler, ProfilerStart,, AC_MSG_ERROR([please install https://github.com/gperftools/gperftools])) PC_REQUIRES_PRIVATE="$PC_REQUIRES_PRIVATE libprofiler" fi]) AC_ARG_WITH([crypto], AS_HELP_STRING([--without-crypto], [ignore presence of OpenSSL and disable it])) AS_IF([test "x$with_crypto" != "xno"], [ AC_CHECK_HEADERS([openssl/evp.h],, [have_crypto=no]) AC_CHECK_HEADERS([openssl/asn1.h],, [have_crypto=no]) AC_CHECK_HEADERS([openssl/crypto.h],, [have_crypto=no]) AC_CHECK_HEADERS([openssl/bio.h],, [have_crypto=no]) AC_CHECK_HEADERS([openssl/pkcs7.h],, [have_crypto=no]) AC_CHECK_HEADERS([openssl/x509.h],, [have_crypto=no]) AC_CHECK_HEADERS([openssl/safestack.h],, [have_crypto=no]) AC_CHECK_LIB(crypto, EVP_DigestInit,, [have_crypto=no]) AC_CHECK_LIB(crypto, EVP_DigestUpdate,, [have_crypto=no]) AC_CHECK_LIB(crypto, EVP_DigestFinal,, [have_crypto=no]) AC_CHECK_LIB(crypto, EVP_md5,, [have_crypto=no]) AC_CHECK_LIB(crypto, EVP_sha1,, [have_crypto=no]) AC_CHECK_LIB(crypto, EVP_sha256,, [have_crypto=no]) ], [ have_crypto=no ]) AS_IF([test "x$have_crypto" = "xno"], [ AS_IF([test "x$with_crypto" = "xyes"], [ AC_MSG_ERROR([please install OpenSSL library]) ], [ AC_MSG_WARN([ ***************************************************************** Could not find OpenSSL library. Some features in "pe" module have been disabled. If you want to enable all features please install OpenSSL and run this script again. ***************************************************************** ]) AC_MSG_CHECKING([for Microsoft Crypto API]) AC_CHECK_HEADERS([wincrypt.h], [ AC_MSG_RESULT([The "hash" module functions will be provided through the Microsoft Crypto API]) # FIXME: Add PC_LIBS_PRIVATE entries? build_hash_module=true ], [], [#include ]) AC_MSG_CHECKING([for MacOSX Common Crypto API]) AC_CHECK_HEADERS([CommonCrypto/CommonCrypto.h], [ AC_MSG_RESULT([ ***************************************************************** As an alternative to OpenSSL the "hash" module functions will be provided through the MacOSX Common Crypto API. ***************************************************************** ]) # FIXME: Add PC_LIBS_PRIVATE entries? build_hash_module=true ]) AS_IF([test x$build_hash_module = xtrue], [ build_hash_module=true CFLAGS="$CFLAGS -DHASH_MODULE" ], [ AC_MSG_WARN([ ***************************************************************** Could not find alternative APIs for hash functions. The "hash" module has been disabled. ***************************************************************** ]) ]) ]) ], [ build_authenticode_module=true # Authenticode relies on openssl build_hash_module=true CFLAGS="$CFLAGS -DHASH_MODULE" PC_REQUIRES_PRIVATE="$PC_REQUIRES_PRIVATE libcrypto" ]) AM_CONDITIONAL([GCC], [test "x$GCC" = xyes]) AM_CONDITIONAL([PROTOC], [test "x${PROTOC}" != "x"]) AM_CONDITIONAL([DEBUG], [test x$debug = xtrue]) AM_CONDITIONAL([GCOV], [test x$gcov = xtrue]) AM_CONDITIONAL([POSIX], [test x$posix = xtrue]) AM_CONDITIONAL([PROFILING_ENABLED], [test x$profiling_enabled = xtrue]) AM_CONDITIONAL([OPTIMIZATION], [test x$optimization = xtrue]) AM_CONDITIONAL([ADDRESS_SANITIZER], [test x$address_sanitizer = xtrue]) AM_CONDITIONAL([UB_SANITIZER], [test x$undefined_behaviour_sanitizer = xtrue]) AM_CONDITIONAL([CUCKOO_MODULE], [test x$build_cuckoo_module = xtrue]) AM_CONDITIONAL([MAGIC_MODULE], [test x$build_magic_module = xtrue]) AM_CONDITIONAL([HASH_MODULE], [test x$build_hash_module = xtrue]) AM_CONDITIONAL([AUTHENTICODE_MODULE], [test x$build_authenticode_module = xtrue]) AM_CONDITIONAL([DOTNET_MODULE], [test x$build_dotnet_module = xtrue]) AM_CONDITIONAL([MACHO_MODULE], [test x$build_macho_module = xtrue]) AM_CONDITIONAL([PB_TESTS_MODULE], [test x$build_pb_tests_module = xtrue]) AM_CONDITIONAL([DEX_MODULE], [test x$build_dex_module = xtrue]) AM_CONDITIONAL([DEBUG_DEX_MODULE], [test x$debug_dex_module = xtrue]) AM_CONDITIONAL([USE_WINDOWS_PROC], [test x$proc_interface = xwindows ]) AM_CONDITIONAL([USE_LINUX_PROC], [test x$proc_interface = xlinux ]) AM_CONDITIONAL([USE_FREEBSD_PROC], [test x$proc_interface = xfreebsd ]) AM_CONDITIONAL([USE_OPENBSD_PROC], [test x$proc_interface = xopenbsd ]) AM_CONDITIONAL([USE_MACH_PROC], [test x$proc_interface = xmach ]) AM_CONDITIONAL([USE_NO_PROC], [test x$proc_interface = xnone ]) AS_IF( [test x$proc_interface != xnone],[AC_DEFINE([HAVE_SCAN_PROC_IMPL],[1])], [test x$proc_interface = xnone],[AC_DEFINE([HAVE_SCAN_PROC_IMPL],[0])]) # Configure TLSH function CFLAGS="$CFLAGS -DBUCKETS_128=1 -DCHECKSUM_1B=1" AC_SUBST([PC_REQUIRES_PRIVATE]) AC_SUBST([PC_LIBS_PRIVATE]) AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([yara.pc]) AC_OUTPUT yara-4.5.3/dist/000077500000000000000000000000001501365277300134335ustar00rootroot00000000000000yara-4.5.3/dist/yara-python.spec000066400000000000000000000020351501365277300165620ustar00rootroot00000000000000%define name yara-python %define version 3.2.0 %define unmangled_version 3.2.0 %define release 1 Summary: Python bindings for YARA malware research tool Name: %{name} Version: %{version} Release: %{release} Source0: %{name}-%{unmangled_version}.tar.gz License: Apache License 2.0 Group: Development/Libraries BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot Prefix: %{_prefix} Vendor: Victor M. Alvarez BuildRequires: gcc python-devel BuildRequires: libyara-devel %description YARA is a tool aimed at (but not limited to) helping malware researchers to identify and classify malware samples. With YARA you can create descriptions of malware families (or whatever you want to describe) based on textual or binary patterns. %prep %setup -n %{name}-%{unmangled_version} %build env CFLAGS="$RPM_OPT_FLAGS" python setup.py build %install python setup.py install -O1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES %clean rm -rf $RPM_BUILD_ROOT %files -f INSTALLED_FILES %defattr(-,root,root) yara-4.5.3/dist/yara.spec000066400000000000000000000053031501365277300152440ustar00rootroot00000000000000## ## Copyright (c) 2007-2015. The YARA Authors. All Rights Reserved. ## 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. ## Name: yara Version: 3.2.0 Release: 1 License: Apache License 2.0 Summary: A malware identification and classification tool Url: http://plusvic.github.io/yara/ Group: System/Filesystems Source: yara-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: autoconf automake libtool %description YARA is a tool aimed at helping malware researchers to identify and classify malware samples. With YARA you can create descriptions of malware families based on textual or binary patterns contained on samples of those families. %package -n libyara Summary: Library to support the yara malware identification tool Group: System/Libraries %description -n libyara YARA is a tool aimed at helping malware researchers to identify and classify malware samples. With YARA you can create descriptions of malware families based on textual or binary patterns contained on samples of those families. %package -n yara-devel Summary: Development files to support the yara malware identification tool Group: Development/Libraries/C and C++ Requires: libyara = %{version}-%{release} %description -n yara-devel YARA is a tool aimed at helping malware researchers to identify and classify malware samples. With YARA you can create descriptions of malware families based on textual or binary patterns contained on samples of those families. %prep %setup -q %build ./bootstrap.sh ./configure make %install make install DESTDIR=%{buildroot} bindir=%{_bindir} libdir=%{_libdir} includedir=%{_includedir} mandir=%{_mandir} INSTALL="install -p" %post -n libyara -p /sbin/ldconfig %postun -n libyara -p /sbin/ldconfig %files %defattr(-,root,root) %{_bindir}/yara %{_bindir}/yarac %{_mandir}/man1/* %files -n libyara %defattr(-,root,root) %{_libdir}/libyara.so* %{_libdir}/pkgconfig/yara.pc %files -n yara-devel %defattr(-,root,root) %{_includedir}/yara.h %{_includedir}/yara/* %{_libdir}/libyara.a %{_libdir}/libyara.la %changelog * Sat Jan 25 2015 Domingo Kiser 3.2.0-1 Initial Creation. yara-4.5.3/docs/000077500000000000000000000000001501365277300134205ustar00rootroot00000000000000yara-4.5.3/docs/Makefile000066400000000000000000000151421501365277300150630ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/yara.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/yara.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/yara" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/yara" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." yara-4.5.3/docs/capi.rst000066400000000000000000001104411501365277300150670ustar00rootroot00000000000000********* The C API ********* You can integrate YARA into your C/C++ project by using the API provided by the *libyara* library. This API gives you access to every YARA feature and it's the same API used by the command-line tools ``yara`` and ``yarac``. Initializing and finalizing *libyara* ===================================== The first thing your program must do when using *libyara* is initializing the library. This is done by calling the :c:func:`yr_initialize` function. This function allocates any resources needed by the library and initializes internal data structures. Its counterpart is :c:func:`yr_finalize`, which must be called when you are finished using the library. In a multi-threaded program only the main thread must call :c:func:`yr_initialize` and :c:func:`yr_finalize`. No additional work is required from other threads using the library. Compiling rules =============== Before using your rules to scan any data you need to compile them into binary form. For that purpose you'll need a YARA compiler, which can be created with :c:func:`yr_compiler_create`. After being used, the compiler must be destroyed with :c:func:`yr_compiler_destroy`. You can use :c:func:`yr_compiler_add_file`, :c:func:`yr_compiler_add_fd`, or :c:func:`yr_compiler_add_string` to add one or more input sources to be compiled. Both of these functions receive an optional namespace. Rules added under the same namespace behave as if they were contained within the same source file or string, so, rule identifiers must be unique among all the sources sharing a namespace. If the namespace argument is ``NULL`` the rules are put in the *default* namespace. The :c:func:`yr_compiler_add_file`, :c:func:`yr_compiler_add_fd`, and :c:func:`yr_compiler_add_string` functions return the number of errors found in the source code. If the rules are correct they will return 0. If any of these functions return an error the compiler can't be used anymore, neither for adding more rules nor getting the compiled rules. For obtaining detailed error information you must set a callback function by using :c:func:`yr_compiler_set_callback` before calling any of the compiling functions. The callback function has the following prototype: .. code-block:: c void callback_function( int error_level, const char* file_name, int line_number, const YR_RULE* rule, const char* message, void* user_data) .. versionchanged:: 4.0.0 Possible values for ``error_level`` are ``YARA_ERROR_LEVEL_ERROR`` and ``YARA_ERROR_LEVEL_WARNING``. The arguments ``file_name`` and ``line_number`` contain the file name and line number where the error or warning occurred. ``file_name`` is the one passed to :c:func:`yr_compiler_add_file` or :c:func:`yr_compiler_add_fd`. It can be ``NULL`` if you passed ``NULL`` or if you're using :c:func:`yr_compiler_add_string`. `rule` is a pointer to the `YR_RULE` structure representing the rule that contained the error, but it can be `NULL` it the error is not contained in a specific rule. The ``user_data`` pointer is the same you passed to :c:func:`yr_compiler_set_callback`. By default, for rules containing references to other files (``include "filename.yara"``), YARA will try to find those files on disk. However, if you want to fetch the imported rules from another source (eg: from a database or remote service), a callback function can be set with :c:func:`yr_compiler_set_include_callback`. This callback receives the following parameters: * ``include_name``: name of the requested file. * ``calling_rule_filename``: the requesting file name (NULL if not a file). * ``calling_rule_namespace``: namespace (NULL if undefined). * ``user_data`` same pointer passed to :c:func:`yr_compiler_set_include_callback`. It should return the requested file's content as a null-terminated string. The memory for this string should be allocated by the callback function. Once it is safe to free the memory used to return the callback's result, the include_free function passed to :c:func:`yr_compiler_set_include_callback` will be called. If the memory does not need to be freed, NULL can be passed as include_free instead. You can completely disable support for includes by setting a NULL callback function with :c:func:`yr_compiler_set_include_callback`. The callback function has the following prototype: .. code-block:: c const char* include_callback( const char* include_name, const char* calling_rule_filename, const char* calling_rule_namespace, void* user_data); The free function has the following prototype: .. code-block:: c void include_free( const char* callback_result_ptr, void* user_data); After you successfully added some sources you can get the compiled rules using the :c:func:`yr_compiler_get_rules` function. You'll get a pointer to a :c:type:`YR_RULES` structure which can be used to scan your data as described in :ref:`scanning-data`. Once :c:func:`yr_compiler_get_rules` is invoked you can not add more sources to the compiler, but you can call :c:func:`yr_compiler_get_rules` multiple times. Each time this function is called it returns a pointer to the same :c:type:`YR_RULES` structure. Notice that this behaviour is new in YARA 4.0.0, in YARA 3.X and 2.X :c:func:`yr_compiler_get_rules` returned a new copy the :c:type:`YR_RULES` structure. Instances of :c:type:`YR_RULES` must be destroyed with :c:func:`yr_rules_destroy`. Defining external variables =========================== If your rules make use of external variables (like in the example below), you must define those variables by using any of the ``yr_compiler_define_XXXX_variable`` functions. Variables must be defined before rules are compiled with ``yr_compiler_add_XXXX`` and they must be defined with a type that matches the context in which the variable is used in the rule, a variable that is used like `my_var == 5` can't be defined as a string variable. While defining external variables with ``yr_compiler_define_XXXX_variable`` you must provide a value for each variable. That value is embedded in the compiled rules and used whenever the variable appears in a rule. However, you can change the value associated to an external variable after the rules has been compiled by using any of the ``yr_rules_define_XXXX_variable`` functions. Saving and retrieving compiled rules ==================================== Compiled rules can be saved to a file and retrieved later by using :c:func:`yr_rules_save` and :c:func:`yr_rules_load`. Rules compiled and saved in one machine can be loaded in another machine as long as they have the same endianness, no matter the operating system or if they are 32-bit or 64-bit systems. However files saved with older versions of YARA may not work with newer versions due to changes in the file layout. You can also save and retrieve your rules to and from generic data streams by using functions :c:func:`yr_rules_save_stream` and :c:func:`yr_rules_load_stream`. These functions receive a pointer to a :c:type:`YR_STREAM` structure, defined as: .. code-block:: c typedef struct _YR_STREAM { void* user_data; YR_STREAM_READ_FUNC read; YR_STREAM_WRITE_FUNC write; } YR_STREAM; You must provide your own implementation for ``read`` and ``write`` functions. The ``read`` function is used by :c:func:`yr_rules_load_stream` to read data from your stream and the ``write`` function is used by :c:func:`yr_rules_save_stream` to write data into your stream. Your ``read`` and ``write`` functions must respond to these prototypes: .. code-block:: c size_t read( void* ptr, size_t size, size_t count, void* user_data); size_t write( const void* ptr, size_t size, size_t count, void* user_data); The ``ptr`` argument is a pointer to the buffer where the ``read`` function should put the read data, or where the ``write`` function will find the data that needs to be written to the stream. In both cases ``size`` is the size of each element being read or written and ``count`` the number of elements. The total size of the data being read or written is ``size`` * ``count``. The ``read`` function must return the number of elements read, the ``write`` function must return the total number of elements written. The ``user_data`` pointer is the same you specified in the :c:type:`YR_STREAM` structure. You can use it to pass arbitrary data to your ``read`` and ``write`` functions. .. _scanning-data: Scanning data ============= Once you have an instance of :c:type:`YR_RULES` you can use it directly with one of the ``yr_rules_scan_XXXX`` functions described below, or create a scanner with :c:func:`yr_scanner_create`. Let's start by discussing the first approach. The :c:type:`YR_RULES` you got from the compiler can be used with :c:func:`yr_rules_scan_file`, :c:func:`yr_rules_scan_fd` or :c:func:`yr_rules_scan_mem` for scanning a file, a file descriptor and a in-memory buffer respectively. The results from the scan are returned to your program via a callback function. The callback has the following prototype: .. code-block:: c int callback_function( YR_SCAN_CONTEXT* context, int message, void* message_data, void* user_data); Possible values for ``message`` are:: CALLBACK_MSG_RULE_MATCHING CALLBACK_MSG_RULE_NOT_MATCHING CALLBACK_MSG_SCAN_FINISHED CALLBACK_MSG_IMPORT_MODULE CALLBACK_MSG_MODULE_IMPORTED CALLBACK_MSG_TOO_MANY_MATCHES CALLBACK_MSG_CONSOLE_LOG Your callback function will be called once for each rule with either a ``CALLBACK_MSG_RULE_MATCHING`` or ``CALLBACK_MSG_RULE_NOT_MATCHING`` message, depending if the rule is matching or not. In both cases a pointer to the :c:type:`YR_RULE` structure associated with the rule is passed in the ``message_data`` argument. You just need to perform a typecast from ``void*`` to ``YR_RULE*`` to access the structure. You can control whether or not YARA calls your callback function with ``CALLBACK_MSG_RULE_MATCHING`` and ``CALLBACK_MSG_RULE_NOT_MATCHING`` messages by using the ``SCAN_FLAGS_REPORT_RULES_MATCHING`` and ``SCAN_FLAGS_REPORT_RULES_NOT_MATCHING`` as described later in this section. This callback is also called with the ``CALLBACK_MSG_IMPORT_MODULE`` message. All modules referenced by an ``import`` statement in the rules are imported once for every file being scanned. In this case ``message_data`` points to a :c:type:`YR_MODULE_IMPORT` structure. This structure contains a ``module_name`` field pointing to a null terminated string with the name of the module being imported and two other fields ``module_data`` and ``module_data_size``. These fields are initially set to ``NULL`` and ``0``, but your program can assign a pointer to some arbitrary data to ``module_data`` while setting ``module_data_size`` to the size of the data. This way you can pass additional data to those modules requiring it, like the :ref:`Cuckoo-module` for example. Once a module is imported the callback is called again with the CALLBACK_MSG_MODULE_IMPORTED. When this happens ``message_data`` points to a :c:type:`YR_OBJECT_STRUCTURE` structure. This structure contains all the information provided by the module about the currently scanned file. If during the scan a string hits the maximum number of matches, your callback will be called once with the ``CALLBACK_MSG_TOO_MANY_MATCHES``. When this happens, ``message_data`` is a ``YR_STRING*`` which points to the string which caused the warning. If your callback returns ``CALLBACK_CONTINUE``, the string will be disabled and scanning will continue, otherwise scanning will be halted. Your callback will be called from the console module (:ref:`console-module`) with the ``CALLBACK_MSG_CONSOLE_LOG`` message. When this happens, the ``message_data`` argument will be a ``char*`` that is the string generated by the console module. Your callback can do whatever it wants with this string, including logging it to an external logging source, or printing it to stdout. Lastly, the callback function is also called with the ``CALLBACK_MSG_SCAN_FINISHED`` message when the scan is finished. In this case ``message_data`` is ``NULL``. Notice that you shouldn't call any of the ``yr_rules_scan_XXXX`` functions from within the callback as those functions are not re-entrant. Your callback function must return one of the following values:: CALLBACK_CONTINUE CALLBACK_ABORT CALLBACK_ERROR If it returns ``CALLBACK_CONTINUE`` YARA will continue normally, ``CALLBACK_ABORT`` will abort the scan but the result from the ``yr_rules_scan_XXXX`` function will be ``ERROR_SUCCESS``. On the other hand ``CALLBACK_ERROR`` will abort the scanning too, but the result from ``yr_rules_scan_XXXX`` will be ``ERROR_CALLBACK_ERROR``. The ``user_data`` argument passed to your callback function is the same you passed ``yr_rules_scan_XXXX``. This pointer is not touched by YARA, it's just a way for your program to pass arbitrary data to the callback function. All ``yr_rules_scan_XXXX`` functions receive a ``flags`` argument that allows to tweak some aspects of the scanning process. The supported flags are the following ones: ``SCAN_FLAGS_FAST_MODE`` ``SCAN_FLAGS_NO_TRYCATCH`` ``SCAN_FLAGS_REPORT_RULES_MATCHING`` ``SCAN_FLAGS_REPORT_RULES_NOT_MATCHING`` The ``SCAN_FLAGS_FAST_MODE`` flag makes the scanning a little faster by avoiding multiple matches of the same string when not necessary. Once the string was found in the file it's subsequently ignored, implying that you'll have a single match for the string, even if it appears multiple times in the scanned data. This flag has the same effect of the ``-f`` command-line option described in :ref:`command-line`. ``SCAN_FLAGS_REPORT_RULES_MATCHING`` and ``SCAN_FLAGS_REPORT_RULES_NOT_MATCHING`` control whether the callback is invoked for rules that are matching or for rules that are not matching respectively. If ``SCAN_FLAGS_REPORT_RULES_MATCHING`` is specified alone, the callback will be called for matching rules with the ``CALLBACK_MSG_RULE_MATCHING`` message but it won't be called for non-matching rules. If ``SCAN_FLAGS_REPORT_RULES_NOT_MATCHING`` is specified alone, the opposite happens, the callback will be called with ``CALLBACK_MSG_RULE_NOT_MATCHING`` messages but not with ``CALLBACK_MSG_RULE_MATCHING`` messages. If both flags are combined together (the default) the callback will be called for both matching and non-matching rules. For backward compatibility, if none of these two flags are specified, the scanner will follow the default behavior. Additionally, ``yr_rules_scan_XXXX`` functions can receive a ``timeout`` argument which forces the scan to abort after the specified number of seconds (approximately). If ``timeout`` is 0 it means no timeout at all. Using a scanner --------------- The ``yr_rules_scan_XXXX`` functions are enough in most cases, but sometimes you may need a fine-grained control over the scanning. In those cases you can create a scanner with :c:func:`yr_scanner_create`. A scanner is simply a wrapper around a :c:type:`YR_RULES` structure that holds additional configuration like external variables without affecting other users of the :c:type:`YR_RULES` structure. A scanner is particularly useful when you want to use the same :c:type:`YR_RULES` with multiple workers (it could be a separate thread, a coroutine, etc) and each worker needs to set different set of values for external variables. In that case you can't use ``yr_rules_define_XXXX_variable`` for setting the values of your external variables, as every worker using the :c:type:`YR_RULES` will be affected by such changes. However each worker can have its own scanner, where the scanners share the same :c:type:`YR_RULES`, and use ``yr_scanner_define_XXXX_variable`` for setting external variables without affecting the rest of the workers. This is a better solution than having a separate :c:type:`YR_RULES` for each worker, as :c:type:`YR_RULES` structures have large memory footprint (specially if you have a lot of rules) while scanners are very lightweight. API reference ============= Data structures --------------- .. c:type:: YR_COMPILER Data structure representing a YARA compiler. .. c:type:: YR_SCAN_CONTEXT Data structure that holds information about an on-going scan. A pointer to this structure is passed to the callback function that receives notifications about matches found. This structure is also used for iterating over the .. c:type:: YR_MATCH Data structure representing a string match. .. c:member:: int64_t base Base offset/address for the match. While scanning a file this field is usually zero, while scanning a process memory space this field is the virtual address of the memory block where the match was found. .. c:member:: int64_t offset Offset of the match relative to *base*. .. c:member:: int32_t match_length Length of the matching string .. c:member:: const uint8_t* data Pointer to a buffer containing a portion of the matching string. .. c:member:: int32_t data_length Length of ``data`` buffer. ``data_length`` is the minimum of ``match_length`` and ``MAX_MATCH_DATA``. .. versionchanged:: 3.5.0 .. c:type:: YR_META Data structure representing a metadata value. .. c:member:: const char* identifier Meta identifier. .. c:member:: int32_t type One of the following metadata types: ``META_TYPE_INTEGER`` ``META_TYPE_STRING`` ``META_TYPE_BOOLEAN`` .. c:type:: YR_MODULE_IMPORT .. c:member:: const char* module_name Name of the module being imported. .. c:member:: void* module_data Pointer to additional data passed to the module. Initially set to ``NULL``, your program is responsible for setting this pointer while handling the CALLBACK_MSG_IMPORT_MODULE message. .. c:member:: size_t module_data_size Size of additional data passed to module. Your program must set the appropriate value if ``module_data`` is modified. .. c:type:: YR_RULE Data structure representing a single rule. .. c:member:: const char* identifier Rule identifier. .. c:member:: const char* tags Pointer to a sequence of null terminated strings with tag names. An additional null character marks the end of the sequence. Example: ``tag1\0tag2\0tag3\0\0``. To iterate over the tags you can use :c:func:`yr_rule_tags_foreach`. .. c:member:: YR_META* metas Pointer to a sequence of :c:type:`YR_META` structures. To iterate over the structures use :c:func:`yr_rule_metas_foreach`. .. c:member:: YR_STRING* strings Pointer to a sequence of :c:type:`YR_STRING` structures. To iterate over the structures use :c:func:`yr_rule_strings_foreach`. .. c:member:: YR_NAMESPACE* ns Pointer to a :c:type:`YR_NAMESPACE` structure. .. c:type:: YR_RULES Data structure representing a set of compiled rules. .. c:type:: YR_STREAM .. versionadded:: 3.4.0 Data structure representing a stream used with functions :c:func:`yr_rules_load_stream` and :c:func:`yr_rules_save_stream`. .. c:member:: void* user_data A user-defined pointer. .. c:member:: YR_STREAM_READ_FUNC read A pointer to the stream's read function provided by the user. .. c:member:: YR_STREAM_WRITE_FUNC write A pointer to the stream's write function provided by the user. .. c:type:: YR_STRING Data structure representing a string declared in a rule. .. c:member:: const char* identifier String identifier. .. c:type:: YR_NAMESPACE Data structure representing a rule namespace. .. c:member:: const char* name Rule namespace. Functions --------- .. c:function:: int yr_initialize(void) Initialize the library. Must be called by the main thread before using any other function. Return :c:macro:`ERROR_SUCCESS` on success another error code in case of error. The list of possible return codes vary according to the modules compiled into YARA. .. c:function:: int yr_finalize(void) Finalize the library. Must be called by the main free to release any resource allocated by the library. Return :c:macro:`ERROR_SUCCESS` on success another error code in case of error. The list of possible return codes vary according to the modules compiled into YARA. .. c:function:: int yr_compiler_create(YR_COMPILER** compiler) Create a YARA compiler. You must pass the address of a pointer to a :c:type:`YR_COMPILER`, the function will set the pointer to the newly allocated compiler. Returns one of the following error codes: :c:macro:`ERROR_SUCCESS` :c:macro:`ERROR_INSUFFICIENT_MEMORY` .. c:function:: void yr_compiler_destroy(YR_COMPILER* compiler) Destroy a YARA compiler. .. c:function:: void yr_compiler_set_callback(YR_COMPILER* compiler, YR_COMPILER_CALLBACK_FUNC callback, void* user_data) .. versionchanged:: 3.3.0 Set a callback for receiving error and warning information. The *user_data* pointer is passed to the callback function. .. c:function:: void yr_compiler_set_include_callback(YR_COMPILER* compiler, YR_COMPILER_INCLUDE_CALLBACK_FUNC callback, YR_COMPILER_INCLUDE_FREE_FUNC include_free, void* user_data) .. versionadded:: 3.7.0 Set a callback to provide rules from a custom source when ``include`` directive is invoked. The *user_data* pointer is untouched and passed back to the callback function and to the free function. Once the callback's result is no longer needed, the include_free function will be called. If the memory does not need to be freed, include_free can be set to NULL. If *callback* is set to ``NULL`` support for include directives is disabled. .. c:function:: int yr_compiler_add_file(YR_COMPILER* compiler, FILE* file, const char* namespace, const char* file_name) Compile rules from a *file*. Rules are put into the specified *namespace*, if *namespace* is ``NULL`` they will be put into the default namespace. *file_name* is the name of the file for error reporting purposes and can be set to ``NULL``. Returns the number of errors found during compilation. .. c:function:: int yr_compiler_add_fd(YR_COMPILER* compiler, YR_FILE_DESCRIPTOR rules_fd, const char* namespace, const char* file_name) .. versionadded:: 3.6.0 Compile rules from a *file descriptor*. Rules are put into the specified *namespace*, if *namespace* is ``NULL`` they will be put into the default namespace. *file_name* is the name of the file for error reporting purposes and can be set to ``NULL``. Returns the number of errors found during compilation. .. c:function:: int yr_compiler_add_string(YR_COMPILER* compiler, const char* string, const char* namespace_) Compile rules from a *string*. Rules are put into the specified *namespace*, if *namespace* is ``NULL`` they will be put into the default namespace. Returns the number of errors found during compilation. .. c:function:: int yr_compiler_get_rules(YR_COMPILER* compiler, YR_RULES** rules) Get the compiled rules from the compiler. Returns one of the following error codes: :c:macro:`ERROR_SUCCESS` :c:macro:`ERROR_INSUFFICIENT_MEMORY` .. c:function:: int yr_compiler_define_integer_variable(YR_COMPILER* compiler, const char* identifier, int64_t value) Define an integer external variable. .. c:function:: int yr_compiler_define_float_variable(YR_COMPILER* compiler, const char* identifier, double value) Define a float external variable. .. c:function:: int yr_compiler_define_boolean_variable(YR_COMPILER* compiler, const char* identifier, int value) Define a boolean external variable. .. c:function:: int yr_compiler_define_string_variable(YR_COMPILER* compiler, const char* identifier, const char* value) Define a string external variable. .. c:function:: int yr_rules_define_integer_variable(YR_RULES* rules, const char* identifier, int64_t value) Define an integer external variable. .. c:function:: int yr_rules_define_boolean_variable(YR_RULES* rules, const char* identifier, int value) Define a boolean external variable. .. c:function:: int yr_rules_define_float_variable(YR_RULES* rules, const char* identifier, double value) Define a float external variable. .. c:function:: int yr_rules_define_string_variable(YR_RULES* rules, const char* identifier, const char* value) Define a string external variable. .. c:function:: void yr_rules_destroy(YR_RULES* rules) Destroy compiled rules. .. c:function:: int yr_rules_save(YR_RULES* rules, const char* filename) Save compiled *rules* into the file specified by *filename*. Only rules obtained from :c:func:`yr_compiler_get_rules` can be saved. Those obtained from :c:func:`yr_rules_load` or :c:func:`yr_rules_load_stream` can not be saved. Returns one of the following error codes: :c:macro:`ERROR_SUCCESS` :c:macro:`ERROR_COULD_NOT_OPEN_FILE` .. c:function:: int yr_rules_save_stream(YR_RULES* rules, YR_STREAM* stream) .. versionadded:: 3.4.0 Save compiled *rules* into *stream*. Only rules obtained from :c:func:`yr_compiler_get_rules` can be saved. Those obtained from :c:func:`yr_rules_load` or :c:func:`yr_rules_load_stream` can not be saved. Returns one of the following error codes: :c:macro:`ERROR_SUCCESS` .. c:function:: int yr_rules_load(const char* filename, YR_RULES** rules) Load compiled rules from the file specified by *filename*. Returns one of the following error codes: :c:macro:`ERROR_SUCCESS` :c:macro:`ERROR_INSUFFICIENT_MEMORY` :c:macro:`ERROR_COULD_NOT_OPEN_FILE` :c:macro:`ERROR_INVALID_FILE` :c:macro:`ERROR_CORRUPT_FILE` :c:macro:`ERROR_UNSUPPORTED_FILE_VERSION` .. c:function:: int yr_rules_load_stream(YR_STREAM* stream, YR_RULES** rules) .. versionadded:: 3.4.0 Load compiled rules from *stream*. Rules loaded this way can not be saved back using :c:func:`yr_rules_save_stream`. Returns one of the following error codes: :c:macro:`ERROR_SUCCESS` :c:macro:`ERROR_INSUFFICIENT_MEMORY` :c:macro:`ERROR_INVALID_FILE` :c:macro:`ERROR_CORRUPT_FILE` :c:macro:`ERROR_UNSUPPORTED_FILE_VERSION` .. c:function:: int yr_rules_scan_mem(YR_RULES* rules, const uint8_t* buffer, size_t buffer_size, int flags, YR_CALLBACK_FUNC callback, void* user_data, int timeout) Scan a memory buffer. Returns one of the following error codes: :c:macro:`ERROR_SUCCESS` :c:macro:`ERROR_INSUFFICIENT_MEMORY` :c:macro:`ERROR_SCAN_TIMEOUT` :c:macro:`ERROR_CALLBACK_ERROR` :c:macro:`ERROR_TOO_MANY_MATCHES` .. c:function:: int yr_rules_scan_file(YR_RULES* rules, const char* filename, int flags, YR_CALLBACK_FUNC callback, void* user_data, int timeout) Scan a file. Returns one of the following error codes: :c:macro:`ERROR_SUCCESS` :c:macro:`ERROR_INSUFFICIENT_MEMORY` :c:macro:`ERROR_COULD_NOT_MAP_FILE` :c:macro:`ERROR_SCAN_TIMEOUT` :c:macro:`ERROR_CALLBACK_ERROR` :c:macro:`ERROR_TOO_MANY_MATCHES` .. c:function:: int yr_rules_scan_fd(YR_RULES* rules, YR_FILE_DESCRIPTOR fd, int flags, YR_CALLBACK_FUNC callback, void* user_data, int timeout) Scan a file descriptor. In POSIX systems ``YR_FILE_DESCRIPTOR`` is an ``int``, as returned by the `open()` function. In Windows ``YR_FILE_DESCRIPTOR`` is a ``HANDLE`` as returned by `CreateFile()`. Returns one of the following error codes: :c:macro:`ERROR_SUCCESS` :c:macro:`ERROR_INSUFFICIENT_MEMORY` :c:macro:`ERROR_COULD_NOT_MAP_FILE` :c:macro:`ERROR_SCAN_TIMEOUT` :c:macro:`ERROR_CALLBACK_ERROR` :c:macro:`ERROR_TOO_MANY_MATCHES` .. c:function:: yr_rule_tags_foreach(rule, tag) Iterate over the tags of a given rule running the block of code that follows each time with a different value for *tag* of type ``const char*``. Example: .. code-block:: c const char* tag; /* rule is a YR_RULE object */ yr_rule_tags_foreach(rule, tag) { ..do something with tag } .. c:function:: yr_rule_metas_foreach(rule, meta) Iterate over the :c:type:`YR_META` structures associated with a given rule running the block of code that follows each time with a different value for *meta*. Example: .. code-block:: c YR_META* meta; /* rule is a YR_RULE object */ yr_rule_metas_foreach(rule, meta) { ..do something with meta } .. c:function:: yr_rule_strings_foreach(rule, string) Iterate over the :c:type:`YR_STRING` structures associated with a given rule running the block of code that follows each time with a different value for *string*. Example: .. code-block:: c YR_STRING* string; /* rule is a YR_RULE object */ yr_rule_strings_foreach(rule, string) { ..do something with string } .. c:function:: yr_string_matches_foreach(context, string, match) Iterate over the :c:type:`YR_MATCH` structures that represent the matches found for a given string during a scan running the block of code that follows, each time with a different value for *match*. The `context` argument is a pointer to a :c:type:`YR_SCAN_CONTEXT` that is passed to the callback function and `string` is a pointer to a :c:type:`YR_STRING`. Example: .. code-block:: c YR_MATCH* match; /* context is a YR_SCAN_CONTEXT* and string is a YR_STRING* */ yr_string_matches_foreach(context, string, match) { ..do something with match } .. c:function:: yr_rules_foreach(rules, rule) Iterate over each :c:type:`YR_RULE` in a :c:type:`YR_RULES` object running the block of code that follows each time with a different value for *rule*. Example: .. code-block:: c YR_RULE* rule; /* rules is a YR_RULES object */ yr_rules_foreach(rules, rule) { ..do something with rule } .. c:function:: void yr_rule_disable(YR_RULE* rule) .. versionadded:: 3.7.0 Disable the specified rule. Disabled rules are completely ignored during the scanning process and they won't match. If the disabled rule is used in the condition of some other rule the value for the disabled rule is neither true nor false but undefined. For more information about undefined values see :ref:`undefined-values`. .. c:function:: void yr_rule_enable(YR_RULE* rule) .. versionadded:: 3.7.0 Enables the specified rule. After being disabled with :c:func:`yr_rule_disable` a rule can be enabled again by using this function. .. c:function:: int yr_scanner_create(YR_RULES* rules, YR_SCANNER **scanner) .. versionadded:: 3.8.0 Creates a new scanner that can be used for scanning data with the provided provided rules. `scanner` must be a pointer to a :c:type:`YR_SCANNER`, the function will set the pointer to the newly allocated scanner. Returns one of the following error codes: :c:macro:`ERROR_INSUFFICIENT_MEMORY` .. c:function:: void yr_scanner_destroy(YR_SCANNER *scanner) .. versionadded:: 3.8.0 Destroy a scanner. After using a scanner it must be destroyed with this function. .. c:function:: void yr_scanner_set_callback(YR_SCANNER *scanner, YR_CALLBACK_FUNC callback, void* user_data) .. versionadded:: 3.8.0 Set a callback function that will be called for reporting any matches found by the scanner. .. c:function:: void yr_scanner_set_timeout(YR_SCANNER* scanner, int timeout) .. versionadded:: 3.8.0 Set the maximum number of seconds that the scanner will spend in any call to `yr_scanner_scan_xxx`. .. c:function:: void yr_scanner_set_flags(YR_SCANNER* scanner, int flags) .. versionadded:: 3.8.0 Set the flags that will be used by any call to `yr_scanner_scan_xxx`. The supported flags are: ``SCAN_FLAGS_FAST_MODE``: Enable fast scan mode. ``SCAN_FLAGS_NO_TRYCATCH``: Disable exception handling. ``SCAN_FLAGS_REPORT_RULES_MATCHING``: If this ``SCAN_FLAGS_REPORT_RULES_NOT_MATCHING`` .. c:function:: int yr_scanner_define_integer_variable(YR_SCANNER* scanner, const char* identifier, int64_t value) .. versionadded:: 3.8.0 Define an integer external variable. .. c:function:: int yr_scanner_define_boolean_variable(YR_SCANNER* scanner, const char* identifier, int value) .. versionadded:: 3.8.0 Define a boolean external variable. .. c:function:: int yr_scanner_define_float_variable(YR_SCANNER* scanner, const char* identifier, double value) .. versionadded:: 3.8.0 Define a float external variable. .. c:function:: int yr_scanner_define_string_variable(YR_SCANNER* scanner, const char* identifier, const char* value) .. versionadded:: 3.8.0 Define a string external variable. .. c:function:: int yr_scanner_scan_mem_blocks(YR_SCANNER* scanner, YR_MEMORY_BLOCK_ITERATOR* iterator) .. versionadded:: 3.8.0 Scan a series of memory blocks that are provided by a :c:type:`YR_MEMORY_BLOCK_ITERATOR`. The iterator has a pair of `first` and `next` functions that must return the first and next blocks respectively. When these functions return `NULL` it indicates that there are not more blocks to scan. In YARA 4.1 and later the `first` and `next` functions can return `NULL` and set the `last_error` field in :c:type:`YR_MEMORY_BLOCK_ITERATOR` to :c:macro:`ERROR_BLOCK_NOT_READY`. This indicates that the iterator is not able to return the next block yet, but the operation may be retried. In such cases `yr_scanner_scan_mem_blocks` also returns :c:macro:`ERROR_BLOCK_NOT_READY` but the scanner maintains its state and this function can be called again for continuing the scanning where it was left. This can be done multiple times until the block is ready and the iterator is able to return it. Notice however that once the iterator completes a full iteration, any subsequent iteration should proceed without returning :c:macro:`ERROR_BLOCK_NOT_READY`. During the first iteration the iterator should store in memory any information that it needs about the blocks, so that it can be iterated again without relying on costly operations that may result in a :c:macro:`ERROR_BLOCK_NOT_READY` error. Returns one of the following error codes: :c:macro:`ERROR_SUCCESS` :c:macro:`ERROR_INSUFFICIENT_MEMORY` :c:macro:`ERROR_SCAN_TIMEOUT` :c:macro:`ERROR_CALLBACK_ERROR` :c:macro:`ERROR_TOO_MANY_MATCHES` :c:macro:`ERROR_BLOCK_NOT_READY` .. c:function:: int yr_scanner_scan_mem(YR_SCANNER* scanner, const uint8_t* buffer, size_t buffer_size) .. versionadded:: 3.8.0 Scan a memory buffer. Returns one of the following error codes: :c:macro:`ERROR_SUCCESS` :c:macro:`ERROR_INSUFFICIENT_MEMORY` :c:macro:`ERROR_SCAN_TIMEOUT` :c:macro:`ERROR_CALLBACK_ERROR` :c:macro:`ERROR_TOO_MANY_MATCHES` .. c:function:: int yr_scanner_scan_file(YR_SCANNER* scanner, const char* filename) .. versionadded:: 3.8.0 Scan a file. Returns one of the following error codes: :c:macro:`ERROR_SUCCESS` :c:macro:`ERROR_INSUFFICIENT_MEMORY` :c:macro:`ERROR_SCAN_TIMEOUT` :c:macro:`ERROR_CALLBACK_ERROR` :c:macro:`ERROR_TOO_MANY_MATCHES` .. c:function:: int yr_scanner_scan_fd(YR_SCANNER* scanner, YR_FILE_DESCRIPTOR fd) .. versionadded:: 3.8.0 Scan a file descriptor. In POSIX systems ``YR_FILE_DESCRIPTOR`` is an ``int``, as returned by the `open()` function. In Windows ``YR_FILE_DESCRIPTOR`` is a ``HANDLE`` as returned by `CreateFile()`. Returns one of the following error codes: :c:macro:`ERROR_SUCCESS` :c:macro:`ERROR_INSUFFICIENT_MEMORY` :c:macro:`ERROR_SCAN_TIMEOUT` :c:macro:`ERROR_CALLBACK_ERROR` :c:macro:`ERROR_TOO_MANY_MATCHES` .. c:function:: YR_RULE* yr_scanner_last_error_rule(YR_SCANNER* scanner) .. versionadded:: 3.8.0 Return a pointer to the ``YR_RULE`` which triggered a scanning error. In the case where the rule is unable to be determined, NULL is returned. .. c:function:: YR_STRING* yr_scanner_last_error_string(YR_SCANNER* scanner) .. versionadded:: 3.8.0 Return a pointer to the ``YR_STRING`` which triggered a scanning error. Error codes ----------- .. c:macro:: ERROR_SUCCESS Everything went fine. .. c:macro:: ERROR_INSUFFICIENT_MEMORY Insufficient memory to complete the operation. .. c:macro:: ERROR_COULD_NOT_OPEN_FILE File could not be opened. .. c:macro:: ERROR_COULD_NOT_MAP_FILE File could not be mapped into memory. .. c:macro:: ERROR_INVALID_FILE File is not a valid rules file. .. c:macro:: ERROR_CORRUPT_FILE Rules file is corrupt. .. c:macro:: ERROR_UNSUPPORTED_FILE_VERSION File was generated by a different YARA and can't be loaded by this version. .. c:macro:: ERROR_SCAN_TIMEOUT Scan timed out. .. c:macro:: ERROR_CALLBACK_ERROR Callback returned an error. .. c:macro:: ERROR_TOO_MANY_MATCHES Too many matches for some string in your rules. This usually happens when your rules contains very short or very common strings like ``01 02`` or ``FF FF FF FF``. The limit is defined by ``YR_MAX_STRING_MATCHES`` in *./include/yara/limits.h* .. c:macro:: ERROR_BLOCK_NOT_READY Next memory block to scan is not ready; custom iterators may return this. yara-4.5.3/docs/commandline.rst000066400000000000000000000127751501365277300164540ustar00rootroot00000000000000.. _command-line: ********************************** Running YARA from the command-line ********************************** In order to invoke YARA you’ll need two things: a file with the rules you want to use and the target to be scanned. The target can be a file, a folder, or a process. :: yara [OPTIONS] RULES_FILE TARGET In YARA 3.8 and below ``RULES_FILE`` was allowed to be a file with rules in source form or in compiled form indistinctly. In YARA 3.9 you need to explicitly specify that ``RULES_FILE`` contains compiled rules by using the -C flag. :: yara [OPTIONS] -C RULES_FILE TARGET This is a security measure to prevent users from inadvertently using compiled rules coming from a third-party. Using compiled rules from untrusted sources can lead to the execution of malicious code in your computer. For compiling rules beforehand you can use the ``yarac`` tool. This way can save time, because for YARA it is faster to load compiled rules than compiling the same rules over and over again. You can also pass multiple source files to `yara` like in the following example:: yara [OPTIONS] RULES_FILE_1 RULES_FILE_2 RULES_FILE_3 TARGET Notice however that this only works for rules in source form. When invoking YARA with compiled rules a single file is accepted. In the example above all rules share the same "default" namespace, which means that rule identifiers must be unique among all files. However you can specify a namespace for individual files. For example :: yara [OPTIONS] namespace1:RULES_FILE_1 RULES_FILE_2 RULES_FILE_3 TARGET In this case ``RULE_FILE_1`` uses ``namespace1`` while ``RULES_FILE_2`` and ``RULES_FILE_3`` share the default namespace. In all cases rules will be applied to the target specified as the last argument to YARA, if it’s a path to a directory all the files contained in it will be scanned. By default YARA does not attempt to scan directories recursively, but you can use the ``-r`` option for that. Available options are: .. program:: yara .. option:: -C --compiled-rules RULES_FILE contains rules already compiled with yarac. .. option:: -c --count Print only number of matches. .. option:: -d = --define=identifier=value Define external variable. This option can be used multiple times. .. option:: -q --disable-console-logs Disable printing console log messages. .. option:: --fail-on-warnings Treat warnings as errors. Has no effect if used with --no-warnings. .. option:: -f --fast-scan Fast matching mode. .. option:: -h --help Show help. .. option:: -i --identifier= Print rules named and ignore the rest. .. option:: --max-process-memory-chunk= When scanning process memory read the data in chunks of the given size. .. option:: -l --max-rules= Abort scanning after matching a number of rules. .. option:: --max-strings-per-rule= Set maximum number of strings per rule (default=10000). If a rule has more then the specified number of strings an error will occur. .. versionadded:: 3.7.0 .. option:: -x = --module-data== Pass the content of as data to . Example: -x cuckoo=/cuckoo_report.json. .. option:: -n --negate Print not satisfied rules only (negate). .. option:: -N --no-follow-symlinks Do not follow symlinks when scanning. .. option:: -w --no-warnings Disable warnings. .. option:: -m --print-meta Print metadata. .. option:: -D --print-module-data Print module data. .. option:: -e --print-namespace Print rules' namespace. .. option:: -S --print-stats Print rules' statistics. .. option:: -s --print-strings Print matching strings. .. option:: -L --print-string-length Print length of matching strings. .. option:: -g --print-tags Print tags. .. option:: -r --recursive Recursively search for directories. It follows symlinks. .. option:: --scan-list Scan files listed in FILE, one per line. .. option:: --strict-escape Print warnings if a string contains an invalid escape sequence. .. versionadded:: 4.5.0 .. option:: -z --skip-larger= Skip files larger than the given in bytes when scanning a directory. .. versionadded:: 4.2.0 .. option:: -k --stack-size= Allocate a stack size of "slots" number of slots. Default: 16384. This will allow you to use larger rules, albeit with more memory overhead. .. versionadded:: 3.5.0 .. option:: -t --tag= Print rules tagged as and ignore the rest. .. option:: -p --threads= Use the specified of threads to scan a directory. .. option:: -a --timeout= Abort scanning after a number of seconds has elapsed. .. option:: -v --version Show version information. Here you have some examples: * Apply rule in */foo/bar/rules* to all files in the current directory. Subdirectories are not scanned:: yara /foo/bar/rules . * Apply rules in */foo/bar/rules* to *bazfile*. Only reports rules tagged as *Packer* or *Compiler*:: yara -t Packer -t Compiler /foo/bar/rules bazfile * Scan all files in the */foo* directory and its subdirectories:: yara /foo/bar/rules -r /foo * Defines three external variables *mybool*, *myint* and *mystring*:: yara -d mybool=true -d myint=5 -d mystring="my string" /foo/bar/rules bazfile * Apply rules in */foo/bar/rules* to *bazfile* while passing the content of *cuckoo_json_report* to the cuckoo module:: yara -x cuckoo=cuckoo_json_report /foo/bar/rules bazfile yara-4.5.3/docs/conf.py000066400000000000000000000201111501365277300147120ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # yara documentation build configuration file, created by # sphinx-quickstart on Tue Jul 8 11:04:03 2014. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys import os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'yara' copyright = u'2014-2022, VirusTotal' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '4.5' # The full version, including alpha/beta/rc tags. release = '4.5.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. try: import sphinx_rtd_theme html_theme = "sphinx_rtd_theme" html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] except: html_theme = "default" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'yaradoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ('index', 'yara.tex', u'yara Documentation', u'Victor M. Alvarez', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'yara', u'yara Documentation', [u'Victor M. Alvarez'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'yara', u'yara Documentation', u'Victor M. Alvarez', 'yara', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False yara-4.5.3/docs/docutils.conf000066400000000000000000000000361501365277300161140ustar00rootroot00000000000000[parsers] smart_quotes: false yara-4.5.3/docs/gettingstarted.rst000066400000000000000000000137601501365277300172110ustar00rootroot00000000000000*************** Getting started *************** YARA is a multi-platform program running on Windows, Linux and Mac OS X. You can find the latest release at https://github.com/VirusTotal/yara/releases. .. _compiling-yara: Compiling and installing YARA ============================= Download the source tarball and get prepared for compiling it:: tar -zxf yara-4.5.0.tar.gz cd yara-4.5.0 ./bootstrap.sh Make sure you have ``automake``, ``libtool``, ``make`` and ``gcc`` and ``pkg-config`` installed in your system. Ubuntu and Debian users can use:: sudo apt-get install automake libtool make gcc pkg-config If you plan to modify YARA's source code you may also need ``flex`` and ``bison`` for generating lexers and parsers:: sudo apt-get install flex bison Compile and install YARA in the standard way:: ./bootstrap.sh ./configure make sudo make install Run the test cases to make sure that everything is fine:: make check Some of YARA's features depend on the OpenSSL library. Those features are enabled only if you have the OpenSSL library installed in your system. If not, YARA is going to work fine but you won't be able to use the disabled features. The ``configure`` script will automatically detect if OpenSSL is installed or not. If you want to enforce the OpenSSL-dependent features you must pass ``--with-crypto`` to the ``configure`` script. Ubuntu and Debian users can use ``sudo apt-get install libssl-dev`` to install the OpenSSL library. The following modules are not compiled into YARA by default: * cuckoo * magic If you plan to use them you must pass the corresponding ``--enable-`` arguments to the ``configure`` script. For example:: ./configure --enable-cuckoo ./configure --enable-magic ./configure --enable-cuckoo --enable-magic Modules usually depend on external libraries, depending on the modules you choose to install you'll need the following libraries: * cuckoo: Depends on `Jansson `_ for parsing JSON. Some Ubuntu and Debian versions already include a package named ``libjansson-dev``, if ``sudo apt-get install libjansson-dev`` doesn't work for you then get the source code from `its repository `_. * magic: Depends on *libmagic*, a library used by the Unix standard program `file `_. Ubuntu, Debian and CentOS include a package ``libmagic-dev``. The source code can be found `here `_. Installing with vcpkg --------------------- You can also download and install YARA using the `vcpkg `_ dependency manager:: git clone https://github.com/microsoft/vcpkg.git cd vcpkg ./bootstrap-vcpkg.sh ./vcpkg integrate install vcpkg install yara The YARA port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please `create an issue or pull request `_ on the vcpkg repository. Installing on Windows --------------------- Compiled binaries for Windows in both 32 and 64 bit flavors can be found in the link below. Just download the version you want, unzip the archive, and put the ``yara.exe`` and ``yarac.exe`` binaries anywhere in your disk. `Download Windows binaries `_ To install YARA using `Scoop `_ or `Chocolatey `_, simply type ``scoop install yara`` or ``choco install yara``. The integration with both `Scoop` and `Chocolatey` are not maintained their respective teams, not by the YARA authors. Installing on Mac OS X with Homebrew ------------------------------------ To install YARA using `Homebrew `_, simply type ``brew install yara``. Installing ``yara-python`` ---------------------- If you plan to use YARA from your Python scripts you need to install the ``yara-python`` extension. Please refer to https://github.com/VirusTotal/yara-python for instructions on how to install it. Running YARA for the first time =============================== Now that you have installed YARA you can write a very simple rule and use the command-line tool to scan some file: .. code-block:: sh echo "rule dummy { condition: true }" > my_first_rule yara my_first_rule my_first_rule Don't get confused by the repeated ``my_first_rule`` in the arguments to ``yara``, I'm just passing the same file as both the rules and the file to be scanned. You can pass any file you want to be scanned (second argument). If everything goes fine you should get the following output:: dummy my_first_rule Which means that the file ``my_first_rule`` is matching the rule named ``dummy``. If you get an error like this:: yara: error while loading shared libraries: libyara.so.2: cannot open shared object file: No such file or directory It means that the loader is not finding the ``libyara`` library which is located in ``/usr/local/lib``. In some Linux flavors the loader doesn't look for libraries in this path by default, we must instruct it to do so by adding ``/usr/local/lib`` to the loader configuration file ``/etc/ld.so.conf``:: sudo sh -c 'echo "/usr/local/lib" >> /etc/ld.so.conf' sudo ldconfig On newer Ubuntu releases such as 22.04 LTS, the correct loader configuration is installed via dependencies to ``/etc/ld.so.conf.d/libc.conf``. In this case, the following command alone is sufficient to configure the dynamic linker run-time bindings. sudo ldconfig If you're using Windows PowerShell as your command shell, ``yara my_first_rule my_first_rule`` may return this error:: my_first_rule(1): error: non-ascii character You can avoid this by using the ``Set-Content`` cmdlet to specify ascii output when creating your rule file:: Set-Content -path .\my_first_rule -Value "rule dummy { condition: true }" -Encoding Ascii .\yara my_first_rule my_first_rule yara-4.5.3/docs/index.rst000066400000000000000000000030501501365277300152570ustar00rootroot00000000000000.. yara documentation master file, created by sphinx-quickstart on Tue Jul 8 11:04:03 2014. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Welcome to YARA's documentation! ================================ YARA is a tool aimed at (but not limited to) helping malware researchers to identify and classify malware samples. With YARA you can create descriptions of malware families (or whatever you want to describe) based on textual or binary patterns. Each description, a.k.a. rule, consists of a set of strings and a boolean expression which determine its logic. Let's see an example: .. code-block:: yara rule silent_banker : banker { meta: description = "This is just an example" threat_level = 3 in_the_wild = true strings: $a = {6A 40 68 00 30 00 00 6A 14 8D 91} $b = {8D 4D B0 2B C1 83 C0 27 99 6A 4E 59 F7 F9} $c = "UVODFRYSIHLNWPEJXQZAKCBGMT" condition: $a or $b or $c } The above rule is telling YARA that any file containing one of the three strings must be reported as silent_banker. This is just a simple example, more complex and powerful rules can be created by using wild-cards, case-insensitive strings, regular expressions, special operators and many other features that you'll find explained in this documentation. Contents: .. toctree:: :maxdepth: 3 gettingstarted writingrules modules writingmodules commandline yarapython capi yara-4.5.3/docs/make.bat000066400000000000000000000150511501365277300150270ustar00rootroot00000000000000@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\yara.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\yara.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end yara-4.5.3/docs/modules.rst000066400000000000000000000012221501365277300156170ustar00rootroot00000000000000******* Modules ******* Modules are the method YARA provides for extending its features. They allow you to define data structures and functions which can be used in your rules to express more complex conditions. Here you'll find described some modules officially distributed with YARA, but you can also learn how to write your own modules in the :ref:`writing-modules` section. .. toctree:: :maxdepth: 3 PE ELF Cuckoo Magic Hash Math Dotnet Time Console String yara-4.5.3/docs/modules/000077500000000000000000000000001501365277300150705ustar00rootroot00000000000000yara-4.5.3/docs/modules/console.rst000066400000000000000000000036111501365277300172650ustar00rootroot00000000000000 .. _console-module: ############## Console module ############## .. versionadded:: 4.2.0 The Console module allows you to log information during condition execution. By default, the log messages are sent to stdout but can be handled differently by using the C api (:ref:`scanning-data`). Every function in the console module returns true for the purposes of condition evaluation. This means you must logically and your statements together to get the proper output. For example: .. code-block:: yara import "console" rule example { condition: console.log("Hello") and console.log("World!") } .. c:function:: log(string) Function which sends the string to the main callback. *Example: console.log(pe.imphash())* .. c:function:: log(message, string) Function which sends the message and string to the main callback. *Example: console.log("The imphash is: ", pe.imphash())* .. c:function:: log(integer) Function which sends the integer to the main callback. *Example: console.log(uint32(0))* .. c:function:: log(message, integer) Function which sends the message and integer to the main callback. *Example: console.log("32bits at 0: ", uint32(0))* .. c:function:: log(float) Function which sends the floating point value to the main callback. *Example: console.log(math.entropy(0, filesize))* .. c:function:: log(message, float) Function which sends the message and the floating point value to the main callback. *Example: console.log("Entropy: ", math.entropy(0, filesize))* .. c:function:: hex(integer) Function which sends the integer to the main callback, formatted as a hex string. *Example: console.hex(uint32(0))* .. c:function:: hex(message, integer) Function which sends the integer to the main callback, formatted as a hex string. *Example: console.hex("Hex at 0: ", uint32(0))* yara-4.5.3/docs/modules/cuckoo.rst000066400000000000000000000123371501365277300171130ustar00rootroot00000000000000.. _cuckoo-module: ############# Cuckoo module ############# The Cuckoo module enables you to create YARA rules based on behavioral information generated by `Cuckoo sandbox `_. While scanning a PE file with YARA, you can pass additional information about its behavior to the ``cuckoo`` module and create rules based not only on what it *contains*, but also on what it *does*. .. important:: This module is not built into YARA by default, to learn how to include it refer to :ref:`compiling-yara`. Good news for Windows users: this module is already included in the official Windows binaries. Suppose that you're interested in executable files sending a HTTP request to http://someone.doingevil.com. In previous versions of YARA you had to settle with: .. code-block:: yara rule evil_doer { strings: $evil_domain = "http://someone.doingevil.com" condition: $evil_domain } The problem with this rule is that the domain name could be contained in the file for perfectly valid reasons not related with sending HTTP requests to http://someone.doingevil.com. Furthermore, the malicious executable could contain the domain name ciphered or obfuscated, in which case your rule would be completely useless. But now with the ``cuckoo`` module you can take the behavior report generated for the executable file by your Cuckoo sandbox, pass it alongside the executable file to YARA, and write a rule like this: .. code-block:: yara import "cuckoo" rule evil_doer { condition: cuckoo.network.http_request(/http:\/\/someone\.doingevil\.com/) } Of course you can mix your behavior-related conditions with good old string-based conditions: .. code-block:: yara import "cuckoo" rule evil_doer { strings: $some_string = { 01 02 03 04 05 06 } condition: $some_string and cuckoo.network.http_request(/http:\/\/someone\.doingevil\.com/) } But how do we pass the behavior information to the ``cuckoo`` module? Well, in the case of the command-line tool you must use the ``-x`` option in this way:: $yara -x cuckoo=behavior_report_file rules_file pe_file ``behavior_report_file`` is the path to a file containing the behavior file generated by the Cuckoo sandbox in JSON format. If you are using ``yara-python`` then you must pass the behavior report in the ``modules_data`` argument for the ``match`` method: .. code-block:: python import yara rules = yara.compile('./rules_file') report_file = open('./behavior_report_file') report_data = report_file.read() rules.match(pe_file, modules_data={'cuckoo': bytes(report_data)}) Reference --------- .. default-domain:: c .. type:: network .. function:: http_request(regexp) Function returning true if the program sent a HTTP request to a URL matching the provided regular expression. *Example: cuckoo.network.http_request(/evil\\.com/)* .. function:: http_get(regexp) Similar to :func:`http_request`, but only takes into account GET requests. .. function:: http_post(regexp) Similar to :func:`http_request`, but only takes into account POST requests. .. function:: http_user_agent(regexp) Function returning true if the program sent a HTTP request with a user agent matching the provided regular expression. *Example: cuckoo.network.http_user_agent(/MSIE 6\\.0/)* .. function:: dns_lookup(regexp) Function returning true if the program sent a domain name resolution request for a domain matching the provided regular expression. *Example: cuckoo.network.dns_lookup(/evil\\.com/)* .. function:: host(regexp) Function returning true if the program contacted an IP address matching the provided regular expression. *Example: cuckoo.network.host(/192\\.168\\.1\\.1/)* .. function:: tcp(regexp, port) Function returning true if the program contacted an IP address matching the provided regular expression, over TCP on the provided port number. *Example: cuckoo.network.tcp(/192\\.168\\.1\\.1/, 443)* .. function:: udp(regexp, port) Function returning true if the program contacted an IP address matching the provided regular expression, over UDP on the provided port number. *Example: cuckoo.network.udp(/192\\.168\\.1\\.1/, 53)* .. type:: registry .. function:: key_access(regexp) Function returning true if the program accessed a registry entry matching the provided regular expression. *Example: cuckoo.registry.key_access(/\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run/)* .. type:: filesystem .. function:: file_access(regexp) Function returning true if the program accessed a file matching the provided regular expression. *Example: cuckoo.filesystem.file_access(/autoexec\\.bat/)* .. type:: sync .. function:: mutex(regexp) Function returning true if the program opens or creates a mutex matching the provided regular expression. *Example: cuckoo.sync.mutex(/EvilMutexName/)* yara-4.5.3/docs/modules/dotnet.rst000066400000000000000000000171751501365277300171320ustar00rootroot00000000000000 .. _dotnet-module: ############# dotnet module ############# .. versionadded:: 3.6.0 The dotnet module allows you to create more fine-grained rules for .NET files by using attributes and features of the .NET file format. Let's see some examples: .. code-block:: yara import "dotnet" rule not_exactly_five_streams { condition: dotnet.number_of_streams != 5 } rule blop_stream { condition: for any i in (0..dotnet.number_of_streams - 1): (dotnet.streams[i].name == "#Blop") } Reference --------- .. c:type:: version The version string contained in the metadata root. *Example: dotnet.version == "v2.0.50727"* .. c:type:: module_name The name of the module. *Example: dotnet.module_name == "axs"* .. c:type:: number_of_streams The number of streams in the file. .. c:type:: streams A zero-based array of stream objects, one for each stream contained in the file. Individual streams can be accessed by using the [] operator. Each stream object has the following attributes: .. c:member:: name Stream name. .. c:member:: offset Stream offset. .. c:member:: size Stream size. *Example: dotnet.streams[0].name == "#~"* .. c:type:: number_of_guids The number of GUIDs in the guids array. .. c:type:: guids A zero-based array of strings, one for each GUID. Individual guids can be accessed by using the [] operator. *Example: dotnet.guids[0] == "99c08ffd-f378-a891-10ab-c02fe11be6ef"* .. c:type:: number_of_classes The number of classes in the file. .. c:type:: classes An array of .NET classes stored in the metadata. Individual classes can be accessed using the [] operator. Each class object contains the following attributes: .. c:member:: fullname Class full name. .. c:member:: name Class name. .. c:member:: namespace Class namespace. .. c:member:: visibility Class visibility specifier, options are: ``private`` ``public`` ``protected`` ``internal`` ``private protected`` ``protected internal`` .. c:member:: type Type of the object, options are: ``class`` ``interface`` .. c:member:: abstract Boolean representing if class is abstract. .. c:member:: sealed Boolean representing if class is sealed. .. c:member:: number_of_generic_parameters Number of generic parameters. .. c:member:: generic_parameters A zero-based array of generic parameters name. Individual parameters can be accessed using the [] operator. .. c:member:: number_of_base_types Number of the base types. .. c:member:: base_types A zero-based array of base types name. Individual base types can be accessed using the [] operator. .. c:member:: number_of_methods Number of the methods. .. c:member:: methods A zero-based array of method objects. Individual methods can be accessed by using the [] operator. Each object contains following attributes: .. c:member:: name Method name. .. c:member:: visibility Method visibility specifier, options are: ``private`` ``public`` ``protected`` ``internal`` ``private protected`` ``protected internal`` .. c:member:: static Boolean representing if method is static. .. c:member:: virtual Boolean representing if method is virtual. .. c:member:: final Boolean representing if method is final. .. c:member:: abstract Boolean representing if method is abstract. .. c:member:: return_type Method return type name. .. c:member:: number_of_parameters Number of the method parameters. .. c:member:: parameters A zero-based array of method parameters. Individual parameters can be accessed by using the [] operator. .. c:member:: name Parameter name. .. c:member:: type Parameter type. .. c:member:: number_of_generic_parameters Number of the method generic parameters. .. c:member:: generic_parameters A zero-based array of method generic parameters. Individual parameters can be accessed by using the [] operator. *Example: dotnet.classes[0].fullname == "Launcher.Program"* .. c:type:: number_of_resources The number of resources in the .NET file. These are different from normal PE resources. .. c:type:: resources A zero-based array of resource objects, one for each resource the .NET file has. Individual resources can be accessed by using the [] operator. Each resource object has the following attributes: .. c:member:: offset Offset for the resource data. .. c:member:: length Length of the resource data. .. c:member:: name Name of the resource (string). *Example: uint16be(dotnet.resources[0].offset) == 0x4d5a* .. c:type:: assembly Object for .NET assembly information. .. c:member:: version An object with integer values representing version information for this assembly. Attributes are: ``major`` ``minor`` ``build_number`` ``revision_number`` .. c:member:: name String containing the assembly name. .. c:member:: culture String containing the culture (language/country/region) for this assembly. *Example: dotnet.assembly.name == "Keylogger"* *Example: dotnet.assembly.version.major == 7 and dotnet.assembly.version.minor == 0* .. c:type:: number_of_modulerefs The number of module references in the .NET file. .. c:type:: modulerefs A zero-based array of strings, one for each module reference the .NET file has. Individual module references can be accessed by using the [] operator. *Example: dotnet.modulerefs[0] == "kernel32"* .. c:type:: typelib The typelib of the file. .. c:type:: number_of_constants The number of constants in the .NET file. .. c:type:: constants A zero-based array of strings, one for each constant the .NET file has. Individual constants can be accessed by using the [] operator. .. c:type:: number_of_assembly_refs The number of objects for .NET assembly reference information. .. c:type:: assembly_refs Object for .NET assembly reference information. .. c:member:: version An object with integer values representing version information for this assembly. Attributes are: ``major`` ``minor`` ``build_number`` ``revision_number`` .. c:member:: name String containing the assembly name. .. c:member:: public_key_or_token String containing the public key or token which identifies the author of this assembly. .. c:type:: number_of_user_strings The number of user strings in the file. .. c:type:: user_strings An zero-based array of user strings, one for each stream contained in the file. Individual strings can be accessed by using the [] operator. .. c:type:: number_of_field_offsets The number of fields in the field_offsets array. .. c:type:: field_offsets A zero-based array of integers, one for each field. Individual field offsets can be accessed by using the [] operator. *Example: dotnet.field_offsets[0] == 8675309* .. c:type:: is_dotnet .. versionadded:: 4.2.0 Function returning true if the PE is indeed .NET. *Example: dotnet.is_dotnet* yara-4.5.3/docs/modules/elf.rst000066400000000000000000000224001501365277300163660ustar00rootroot00000000000000 .. _elf-module: ########## ELF module ########## .. versionadded:: 3.2.0 The ELF module is very similar to the :ref:`pe-module`, but for ELF files. This module exposes most of the fields present in an ELF header. Let's see some examples: .. code-block:: yara import "elf" rule single_section { condition: elf.number_of_sections == 1 } rule elf_64 { condition: elf.machine == elf.EM_X86_64 } Reference --------- .. c:type:: type Integer with one of the following values: .. c:type:: ET_NONE No file type. .. c:type:: ET_REL Relocatable file. .. c:type:: ET_EXEC Executable file. .. c:type:: ET_DYN Shared object file. .. c:type:: ET_CORE Core file. *Example: elf.type == elf.ET_EXEC* .. c:type:: machine Integer with one of the following values: .. c:type:: EM_NONE .. c:type:: EM_M32 .. c:type:: EM_SPARC .. c:type:: EM_386 .. c:type:: EM_68K .. c:type:: EM_88K .. c:type:: EM_860 .. c:type:: EM_MIPS .. c:type:: EM_MIPS_RS3_LE .. c:type:: EM_PPC .. c:type:: EM_PPC64 .. c:type:: EM_ARM .. c:type:: EM_X86_64 .. c:type:: EM_AARCH64 *Example: elf.machine == elf.EM_X86_64* .. c:type:: entry_point Entry point raw offset or virtual address depending on whether YARA is scanning a file or process memory respectively. This is equivalent to the deprecated ``entrypoint`` keyword. .. c:type:: number_of_sections Number of sections in the ELF file. .. c:type:: sections A zero-based array of section objects, one for each section the ELF has. Individual sections can be accessed by using the [] operator. Each section object has the following attributes: .. c:member:: name Section's name. *Example: elf.sections[3].name == ".bss"* .. c:member:: size Section's size in bytes. Unless the section type is SHT_NOBITS, the section occupies sh_size bytes in the file. A section of :c:type:`SHT_NOBITS` may have a non-zero size, but it occupies no space in the file. .. c:member:: offset Offset from the beginning of the file to the first byte in the section. One section type, :c:type:`SHT_NOBITS` described below, occupies no space in the file, and its :c:member:`offset` member locates the conceptual placement in the file. .. c:member:: type Integer with one of the following values: .. c:type:: SHT_NULL This value marks the section as inactive; it does not have an associated section. Other members of the section header have undefined values. .. c:type:: SHT_PROGBITS The section holds information defined by the program, whose format and meaning are determined solely by the program. .. c:type:: SHT_SYMTAB The section holds a symbol table. .. c:type:: SHT_STRTAB The section holds a string table. An object file may have multiple string table sections. .. c:type:: SHT_RELA The section holds relocation entries. .. c:type:: SHT_HASH The section holds a symbol hash table. .. c:type:: SHT_DYNAMIC The section holds information for dynamic linking. .. c:type:: SHT_NOTE The section holds information that marks the file in some way. .. c:type:: SHT_NOBITS A section of this type occupies no space in the file but otherwise resembles :c:type:`SHT_PROGBITS`. .. c:type:: SHT_REL The section holds relocation entries. .. c:type:: SHT_SHLIB This section type is reserved but has unspecified semantics. .. c:type:: SHT_DYNSYM This section holds dynamic linking symbols. .. c:member:: flags Integer with section's flags as defined below: .. c:type:: SHF_WRITE The section contains data that should be writable during process execution. .. c:type:: SHF_ALLOC The section occupies memory during process execution. Some control sections do not reside in the memory image of an object file; this attribute is off for those sections. .. c:type:: SHF_EXECINSTR The section contains executable machine instructions. *Example: elf.sections[2].flags & elf.SHF_WRITE* .. c:member:: address .. versionadded:: 3.6.0 The virtual address the section starts at. .. c:type:: number_of_segments .. versionadded:: 3.4.0 Number of segments in the ELF file. .. c:type:: segments .. versionadded:: 3.4.0 A zero-based array of segment objects, one for each segment the ELF has. Individual segments can be accessed by using the [] operator. Each segment object has the following attributes: .. c:member:: alignment Value to which the segments are aligned in memory and in the file. .. c:member:: file_size Number of bytes in the file image of the segment. It may be zero. .. c:member:: flags A combination of the following segment flags: .. c:type:: PF_R The segment is readable. .. c:type:: PF_W The segment is writable. .. c:type:: PF_X The segment is executable. .. c:member:: memory_size In-memory segment size. .. c:member:: offset Offset from the beginning of the file where the segment resides. .. c:member:: physical_address On systems for which physical addressing is relevant, contains the segment's physical address. .. c:member:: type Type of segment indicated by one of the following values: .. c:type:: PT_NULL .. c:type:: PT_LOAD .. c:type:: PT_DYNAMIC .. c:type:: PT_INTERP .. c:type:: PT_NOTE .. c:type:: PT_SHLIB .. c:type:: PT_PHDR .. c:type:: PT_LOPROC .. c:type:: PT_HIPROC .. c:type:: PT_GNU_STACK .. c:member:: virtual_address Virtual address at which the segment resides in memory. .. c:type:: dynamic_section_entries .. versionadded:: 3.6.0 Number of entries in the dynamic section in the ELF file. .. c:type:: dynamic .. versionadded:: 3.6.0 A zero-based array of dynamic objects, one for each entry in found in the ELF's dynamic section. Individual dynamic objects can be accessed by using the [] operator. Each dynamic object has the following attributes: .. c:member:: type Value that describes the type of dynamic section. Builtin values are: .. c:type:: DT_NULL .. c:type:: DT_NEEDED .. c:type:: DT_PLTRELSZ .. c:type:: DT_PLTGOT .. c:type:: DT_HASH .. c:type:: DT_STRTAB .. c:type:: DT_SYMTAB .. c:type:: DT_RELA .. c:type:: DT_RELASZ .. c:type:: DT_RELAENT .. c:type:: DT_STRSZ .. c:type:: DT_SYMENT .. c:type:: DT_INIT .. c:type:: DT_FINI .. c:type:: DT_SONAME .. c:type:: DT_RPATH .. c:type:: DT_SYMBOLIC .. c:type:: DT_REL .. c:type:: DT_RELSZ .. c:type:: DT_RELENT .. c:type:: DT_PLTREL .. c:type:: DT_DEBUG .. c:type:: DT_TEXTREL .. c:type:: DT_JMPREL .. c:type:: DT_BIND_NOW .. c:type:: DT_INIT_ARRAY .. c:type:: DT_FINI_ARRAY .. c:type:: DT_INIT_ARRAYSZ .. c:type:: DT_FINI_ARRAYSZ .. c:type:: DT_RUNPATH .. c:type:: DT_FLAGS .. c:type:: DT_ENCODING .. c:member:: value A value associated with the given type. The type of value (address, size, etc.) is dependant on the type of dynamic entry. .. c:type:: symtab_entries .. versionadded:: 3.6.0 Number of entries in the symbol table found in the ELF file. .. c:type:: symtab .. versionadded:: 3.6.0 A zero-based array of symbol objects, one for each entry in found in the ELF's SYMBTAB. Individual symbol objects can be accessed by using the [] operator. Each symbol object has the following attributes: .. c:member:: name The symbol's name. .. c:member:: value A value associated with the symbol. Generally a virtual address. .. c:member:: size The symbol's size. .. c:member:: type The type of symbol. Built values are: .. c:type:: STT_NOTYPE .. c:type:: STT_OBJECT .. c:type:: STT_FUNC .. c:type:: STT_SECTION .. c:type:: STT_FILE .. c:type:: STT_COMMON .. c:type:: STT_TLS .. c:member:: bind The binding of the symbol. Builtin values are: .. c:type:: STB_LOCAL .. c:type:: STB_GLOBAL .. c:type:: STB_WEAK .. c:member:: shndx The section index which the symbol is associated with. .. c:function:: telfhash() Function returning Telfhash - TLSH hash of the ELF export and import symbols. *Example: elf.telfhash() == "t166a00284751084526486df8b5df5b2fccb3f511dbc188c37156f5e714a11bc5d71014d"* .. c:function:: import_md5() Function returning Import Hash - MD5 hash of the ELF imported symbols. *Example: elf.import_md5() == "c3eca50cbb03400a6e91b9fe48da0c0c"* yara-4.5.3/docs/modules/hash.rst000066400000000000000000000050541501365277300165510ustar00rootroot00000000000000 .. _hash-module: ########### Hash module ########### .. versionadded:: 3.2.0 The Hash module allows you to calculate hashes (MD5, SHA1, SHA256) from portions of your file and create signatures based on those hashes. .. important:: This module depends on the OpenSSL library. Please refer to :ref:`compiling-yara` for information about how to build OpenSSL-dependant features into YARA. Good news for Windows users: this module is already included in the official Windows binaries. .. warning:: The returned hash string is always in lowercase. This means that rule condition matching on hashes ``hash.md5(0, filesize) == "feba6c919e3797e7778e8f2e85fa033d"`` requires the hash string to be given in lowercase, otherwise the match condition will not work. (see https://github.com/VirusTotal/yara/issues/1004) .. c:function:: md5(offset, size) Returns the MD5 hash for *size* bytes starting at *offset*. When scanning a running process the *offset* argument should be a virtual address within the process address space. The returned string is always in lowercase. *Example: hash.md5(0, filesize) == "feba6c919e3797e7778e8f2e85fa033d"* .. c:function:: md5(string) Returns the MD5 hash for the given string. *Example: hash.md5("dummy") == "275876e34cf609db118f3d84b799a790"* .. c:function:: sha1(offset, size) Returns the SHA1 hash for the *size* bytes starting at *offset*. When scanning a running process the *offset* argument should be a virtual address within the process address space. The returned string is always in lowercase. .. c:function:: sha1(string) Returns the SHA1 hash for the given string. .. c:function:: sha256(offset, size) Returns the SHA256 hash for the *size* bytes starting at *offset*. When scanning a running process the *offset* argument should be a virtual address within the process address space. The returned string is always in lowercase. .. c:function:: sha256(string) Returns the SHA256 hash for the given string. .. c:function:: checksum32(offset, size) Returns a 32-bit checksum for the *size* bytes starting at *offset*. The checksum is just the sum of all the bytes (unsigned). .. c:function:: checksum32(string) Returns a 32-bit checksum for the given string. The checksum is just the sum of all the bytes in the string (unsigned). .. c:function:: crc32(offset, size) Returns a crc32 checksum for the *size* bytes starting at *offset*. .. c:function:: crc32(string) Returns a crc32 checksum for the given string. yara-4.5.3/docs/modules/magic.rst000066400000000000000000000037601501365277300167100ustar00rootroot00000000000000 .. _magic-module: ############ Magic module ############ .. versionadded:: 3.1.0 The Magic module allows you to identify the type of the file based on the output of `file `_, the standard Unix command. .. important:: This module is not built into YARA by default, to learn how to include it refer to :ref:`compiling-yara`. Bad news for Windows users: **this module is not supported on Windows**. There are two functions in this module: :c:func:`type` and :c:func:`mime_type`. The first one returns the descriptive string returned by *file*, for example, if you run *file* against some PDF document you'll get something like this:: $file some.pdf some.pdf: PDF document, version 1.5 The :c:func:`type` function would return *"PDF document, version 1.5"* in this case. Using the :c:func:`mime_type` function is similar to passing the ``--mime`` argument to *file*.:: $file --mime some.pdf some.pdf: application/pdf; charset=binary :c:func:`mime_type` would return *"application/pdf"*, without the charset part. By experimenting a little with the *file* command you can learn which output to expect for different file types. These are a few examples: * JPEG image data, JFIF standard 1.01 * PE32 executable for MS Windows (GUI) Intel 80386 32-bit * PNG image data, 1240 x 1753, 8-bit/color RGBA, non-interlaced * ASCII text, with no line terminators * Zip archive data, at least v2.0 to extract libmagic will try and read its compiled file type database from /etc/magic.mgc by default. If this file doesn't exist, you can set the environment variable MAGIC to point to a magic.mgc file and libmagic will attempt to load from there as an alternative. .. c:function:: type() Function returning a string with the type of the file. *Example: magic.type() contains "PDF"* .. c:function:: mime_type() Function returning a string with the MIME type of the file. *Example: magic.mime_type() == "application/pdf"* yara-4.5.3/docs/modules/math.rst000066400000000000000000000136651501365277300165660ustar00rootroot00000000000000 .. _math-module: ########### Math module ########### .. versionadded:: 3.3.0 The Math module allows you to calculate certain values from portions of your file and create signatures based on those results. .. important:: Where noted these functions return floating point numbers. YARA is able to convert integers to floating point numbers during most operations. For example this will convert 7 to 7.0 automatically, because the return type of the entropy function is a floating point value: *math.entropy(0, filesize) >= 7* The one exception to this is when a function requires a floating point number as an argument. For example, this will cause a syntax error because the arguments must be floating point numbers: *math.in_range(2, 1, 3)* .. c:function:: entropy(offset, size) Returns the entropy for *size* bytes starting at *offset*. When scanning a running process the *offset* argument should be a virtual address within the process address space. The returned value is a float. *Example: math.entropy(0, filesize) >= 7* .. c:function:: entropy(string) Returns the entropy for the given string. *Example: math.entropy("dummy") > 7* .. c:function:: monte_carlo_pi(offset, size) Returns the percentage away from Pi for the *size* bytes starting at *offset* when run through the Monte Carlo from Pi test. When scanning a running process the *offset* argument should be a virtual address within the process address space. The returned value is a float. *Example: math.monte_carlo_pi(0, filesize) < 0.07* .. c:function:: monte_carlo_pi(string) Return the percentage away from Pi for the given string. .. c:function:: serial_correlation(offset, size) Returns the serial correlation for the *size* bytes starting at *offset*. When scanning a running process the *offset* argument should be a virtual address within the process address space. The returned value is a float between 0.0 and 1.0. *Example: math.serial_correlation(0, filesize) < 0.2* .. c:function:: serial_correlation(string) Return the serial correlation for the given string. .. c:function:: mean(offset, size) Returns the mean for the *size* bytes starting at *offset*. When scanning a running process the *offset* argument should be a virtual address within the process address space. The returned value is a float. *Example: math.mean(0, filesize) < 72.0* .. c:function:: mean(string) Return the mean for the given string. .. c:function:: deviation(offset, size, mean) Returns the deviation from the mean for the *size* bytes starting at *offset*. When scanning a running process the *offset* argument should be a virtual address within the process address space. The returned value is a float. The mean of an equally distributed random sample of bytes is 127.5, which is available as the constant math.MEAN_BYTES. *Example: math.deviation(0, filesize, math.MEAN_BYTES) == 64.0* .. c:function:: deviation(string, mean) Return the deviation from the mean for the given string. .. c:function:: in_range(test, lower, upper) Returns true if the *test* value is between *lower* and *upper* values. The comparisons are inclusive. *Example: math.in_range(math.deviation(0, filesize, math.MEAN_BYTES), 63.9, 64.1)* .. c:function:: max(int, int) .. versionadded:: 3.8.0 Returns the maximum of two unsigned integer values. .. c:function:: min(int, int) .. versionadded:: 3.8.0 Returns the minimum of two unsigned integer values. .. c:function:: to_number(bool) .. versionadded:: 4.1.0 Returns 0 or 1, it's useful when writing a score based rule. *Example: math.to_number(SubRule1) \* 60 + math.to_number(SubRule2) \* 20 + math.to_number(SubRule3) \* 70 > 80* .. c:function:: abs(int) .. versionadded:: 4.2.0 Returns the absolute value of the signed integer. *Example: math.abs(@a - @b) == 1* .. c:function:: count(byte, offset, size) .. versionadded:: 4.2.0 Returns how often a specific byte occurs, starting at *offset* and looking at the next *size* bytes. When scanning a running process the *offset* argument should be a virtual address within the process address space. *offset* and *size* are optional; if left empty, the complete file is searched. *Example: math.count(0x4A) >= 10* *Example: math.count(0x00, 0, 4) < 2* .. c:function:: percentage(byte, offset, size) .. versionadded:: 4.2.0 Returns the occurrence rate of a specific byte, starting at *offset* and looking at the next *size* bytes. When scanning a running process the *offset* argument should be a virtual address within the process address space. The returned value is a float between 0 and 1. *offset* and *size* are optional; if left empty, the complete file is searched. *Example: math.percentage(0xFF, filesize-1024, filesize) >= 0.9* *Example: math.percentage(0x4A) >= 0.4* .. c:function:: mode(offset, size) .. versionadded:: 4.2.0 Returns the most common byte, starting at *offset* and looking at the next *size* bytes. When scanning a running process the *offset* argument should be a virtual address within the process address space. The returned value is a float. *offset* and *size* are optional; if left empty, the complete file is searched. *Example: math.mode(0, filesize) == 0xFF* *Example: math.mode() == 0x00* .. c:function:: to_string(int) .. versionadded:: 4.3.0 Convert the given integer to a string. Note: integers in YARA are signed. *Example: math.to_string(10) == "10"* *Example: math.to_string(-1) == "-1"* .. c:function:: to_string(int, base) .. versionadded:: 4.3.0 Convert the given integer to a string in the given base. Supported bases are 10, 8 and 16. Note: integers in YARA are signed. *Example: math.to_string(32, 16) == "20"* *Example: math.to_string(-1, 16) == "ffffffffffffffff"* yara-4.5.3/docs/modules/pe.rst000066400000000000000000001207761501365277300162430ustar00rootroot00000000000000 .. _pe-module: ######### PE module ######### The PE module allows you to create more fine-grained rules for PE files by using attributes and features of the PE file format. This module exposes most of the fields present in a PE header and provides functions which can be used to write more expressive and targeted rules. Let's see some examples: .. code-block:: yara import "pe" rule single_section { condition: pe.number_of_sections == 1 } rule control_panel_applet { condition: pe.exports("CPlApplet") } rule is_dll { condition: pe.characteristics & pe.DLL } rule is_pe { condition: pe.is_pe } Reference --------- .. c:type:: machine .. versionchanged:: 3.3.0 Integer with one of the following values: .. c:type:: MACHINE_UNKNOWN .. c:type:: MACHINE_AM33 .. c:type:: MACHINE_AMD64 .. c:type:: MACHINE_ARM .. c:type:: MACHINE_ARMNT .. c:type:: MACHINE_ARM64 .. c:type:: MACHINE_EBC .. c:type:: MACHINE_I386 .. c:type:: MACHINE_IA64 .. c:type:: MACHINE_M32R .. c:type:: MACHINE_MIPS16 .. c:type:: MACHINE_MIPSFPU .. c:type:: MACHINE_MIPSFPU16 .. c:type:: MACHINE_POWERPC .. c:type:: MACHINE_POWERPCFP .. c:type:: MACHINE_R4000 .. c:type:: MACHINE_SH3 .. c:type:: MACHINE_SH3DSP .. c:type:: MACHINE_SH4 .. c:type:: MACHINE_SH5 .. c:type:: MACHINE_THUMB .. c:type:: MACHINE_WCEMIPSV2 .. c:type:: MACHINE_TARGET_HOST .. c:type:: MACHINE_R3000 .. c:type:: MACHINE_R10000 .. c:type:: MACHINE_ALPHA .. c:type:: MACHINE_SH3E .. c:type:: MACHINE_ALPHA64 .. c:type:: MACHINE_AXP64 .. c:type:: MACHINE_TRICORE .. c:type:: MACHINE_CEF .. c:type:: MACHINE_CEE *Example: pe.machine == pe.MACHINE_AMD64* .. c:type:: checksum .. versionadded:: 3.6.0 Integer with the "PE checksum" as stored in the OptionalHeader .. c:type:: calculate_checksum .. versionadded:: 3.6.0 Function that calculates the "PE checksum" *Example: pe.checksum == pe.calculate_checksum()* .. c:type:: subsystem Integer with one of the following values: .. c:type:: SUBSYSTEM_UNKNOWN .. c:type:: SUBSYSTEM_NATIVE .. c:type:: SUBSYSTEM_WINDOWS_GUI .. c:type:: SUBSYSTEM_WINDOWS_CUI .. c:type:: SUBSYSTEM_OS2_CUI .. c:type:: SUBSYSTEM_POSIX_CUI .. c:type:: SUBSYSTEM_NATIVE_WINDOWS .. c:type:: SUBSYSTEM_WINDOWS_CE_GUI .. c:type:: SUBSYSTEM_EFI_APPLICATION .. c:type:: SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER .. c:type:: SUBSYSTEM_EFI_RUNTIME_DRIVER .. c:type:: SUBSYSTEM_EFI_ROM_IMAGE .. c:type:: SUBSYSTEM_XBOX .. c:type:: SUBSYSTEM_WINDOWS_BOOT_APPLICATION *Example: pe.subsystem == pe.SUBSYSTEM_NATIVE* .. c:type:: timestamp PE timestamp, as an epoch integer. *Example: pe.timestamp >= 1424563200* .. c:type:: pointer_to_symbol_table .. versionadded:: 3.8.0 Value of IMAGE_FILE_HEADER::PointerToSymbolTable. Used when the PE image has COFF debug info. .. c:type:: number_of_symbols .. versionadded:: 3.8.0 Value of IMAGE_FILE_HEADER::NumberOfSymbols. Used when the PE image has COFF debug info. .. c:type:: size_of_optional_header .. versionadded:: 3.8.0 Value of IMAGE_FILE_HEADER::SizeOfOptionalHeader. This is real size of the optional header and reflects differences between 32-bit and 64-bit optional header and number of data directories. .. c:type:: opthdr_magic .. versionadded:: 3.8.0 Value of IMAGE_OPTIONAL_HEADER::Magic. Integer with one of the following values: .. c:type:: IMAGE_NT_OPTIONAL_HDR32_MAGIC .. c:type:: IMAGE_NT_OPTIONAL_HDR64_MAGIC .. c:type:: IMAGE_ROM_OPTIONAL_HDR_MAGIC .. c:type:: size_of_code .. versionadded:: 3.8.0 Value of IMAGE_OPTIONAL_HEADER::SizeOfCode. This is the sum of raw data sizes in code sections. .. c:type:: size_of_initialized_data .. versionadded:: 3.8.0 Value of IMAGE_OPTIONAL_HEADER::SizeOfInitializedData. .. c:type:: size_of_uninitialized_data Value of IMAGE_OPTIONAL_HEADER::SizeOfUninitializedData. .. c:type:: entry_point Entry point file offset or virtual address depending on whether YARA is scanning a file or process memory respectively. This is equivalent to the deprecated ``entrypoint`` keyword. .. c:type:: entry_point_raw Entry point raw value from the optional header of the PE. This value is not converted to a file offset or an RVA. .. versionadded:: 4.1.0 .. c:type:: base_of_code .. versionadded:: 3.8.0 Value of IMAGE_OPTIONAL_HEADER::BaseOfCode. .. c:type:: base_of_data .. versionadded:: 3.8.0 Value of IMAGE_OPTIONAL_HEADER::BaseOfData. This field only exists in 32-bit PE files. .. c:type:: image_base Image base relative virtual address. .. c:type:: section_alignment .. versionadded:: 3.8.0 Value of IMAGE_OPTIONAL_HEADER::SectionAlignment. When Windows maps a PE image to memory, all raw sizes (including size of header) are aligned up to this value. .. c:type:: file_alignment .. versionadded:: 3.8.0 Value of IMAGE_OPTIONAL_HEADER::FileAlignment. All raw data sizes of sections in the PE image are aligned to this value. .. c:type:: win32_version_value .. versionadded:: 3.8.0 Value of IMAGE_OPTIONAL_HEADER::Win32VersionValue. .. c:type:: size_of_image .. versionadded:: 3.8.0 Value of IMAGE_OPTIONAL_HEADER::SizeOfImage. This is the total virtual size of header and all sections. .. c:type:: size_of_headers .. versionadded:: 3.8.0 Value of IMAGE_OPTIONAL_HEADER::SizeOfHeaders. This is the raw data size of the PE headers including DOS header, file header, optional header and all section headers. When PE is mapped to memory, this value is subject to aligning up to SectionAlignment. .. c:type:: characteristics Bitmap with PE FileHeader characteristics. Individual characteristics can be inspected by performing a bitwise AND operation with the following constants: .. c:type:: RELOCS_STRIPPED Relocation info stripped from file. .. c:type:: EXECUTABLE_IMAGE File is executable (i.e. no unresolved external references). .. c:type:: LINE_NUMS_STRIPPED Line numbers stripped from file. .. c:type:: LOCAL_SYMS_STRIPPED Local symbols stripped from file. .. c:type:: AGGRESIVE_WS_TRIM Aggressively trim working set .. c:type:: LARGE_ADDRESS_AWARE App can handle >2gb addresses .. c:type:: BYTES_REVERSED_LO Bytes of machine word are reversed. .. c:type:: MACHINE_32BIT 32 bit word machine. .. c:type:: DEBUG_STRIPPED Debugging info stripped from file in .DBG file .. c:type:: REMOVABLE_RUN_FROM_SWAP If Image is on removable media, copy and run from the swap file. .. c:type:: NET_RUN_FROM_SWAP If Image is on Net, copy and run from the swap file. .. c:type:: SYSTEM System File. .. c:type:: DLL File is a DLL. .. c:type:: UP_SYSTEM_ONLY File should only be run on a UP machine .. c:type:: BYTES_REVERSED_HI Bytes of machine word are reversed. *Example: pe.characteristics & pe.DLL* .. c:type:: linker_version An object with two integer attributes, one for each major and minor linker version. .. c:member:: major Major linker version. .. c:member:: minor Minor linker version. .. c:type:: os_version An object with two integer attributes, one for each major and minor OS version. .. c:member:: major Major OS version. .. c:member:: minor Minor OS version. .. c:type:: image_version An object with two integer attributes, one for each major and minor image version. .. c:member:: major Major image version. .. c:member:: minor Minor image version. .. c:type:: subsystem_version An object with two integer attributes, one for each major and minor subsystem version. .. c:member:: major Major subsystem version. .. c:member:: minor Minor subsystem version. .. c:type:: dll_characteristics Bitmap with PE OptionalHeader DllCharacteristics. Do not confuse these flags with the PE FileHeader Characteristics. Individual characteristics can be inspected by performing a bitwise AND operation with the following constants: .. c:type:: HIGH_ENTROPY_VA ASLR with 64 bit address space. .. c:type:: DYNAMIC_BASE File can be relocated - also marks the file as ASLR compatible .. c:type:: FORCE_INTEGRITY .. c:type:: NX_COMPAT Marks the file as DEP compatible .. c:type:: NO_ISOLATION .. c:type:: NO_SEH The file does not contain structured exception handlers, this must be set to use SafeSEH .. c:type:: NO_BIND .. c:type:: APPCONTAINER Image should execute in an AppContainer .. c:type:: WDM_DRIVER Marks the file as a Windows Driver Model (WDM) device driver. .. c:type:: GUARD_CF Image supports Control Flow Guard. .. c:type:: TERMINAL_SERVER_AWARE Marks the file as terminal server compatible .. c:type:: size_of_stack_reserve .. versionadded:: 3.8.0 Value of IMAGE_OPTIONAL_HEADER::SizeOfStackReserve. This is the default amount of virtual memory that will be reserved for stack. .. c:type:: size_of_stack_commit .. versionadded:: 3.8.0 Value of IMAGE_OPTIONAL_HEADER::SizeOfStackCommit. This is the default amount of virtual memory that will be allocated for stack. .. c:type:: size_of_heap_reserve .. versionadded:: 3.8.0 Value of IMAGE_OPTIONAL_HEADER::SizeOfHeapReserve. This is the default amount of virtual memory that will be reserved for main process heap. .. c:type:: size_of_heap_commit .. versionadded:: 3.8.0 Value of IMAGE_OPTIONAL_HEADER::SizeOfHeapCommit. This is the default amount of virtual memory that will be allocated for main process heap. .. c:type:: loader_flags .. versionadded:: 3.8.0 Value of IMAGE_OPTIONAL_HEADER::LoaderFlags. .. c:type:: number_of_rva_and_sizes Value of IMAGE_OPTIONAL_HEADER::NumberOfRvaAndSizes. This is the number of items in the IMAGE_OPTIONAL_HEADER::DataDirectory array. .. c:type:: data_directories .. versionadded:: 3.8.0 A zero-based array of data directories. Each data directory contains virtual address and length of the appropriate data directory. Each data directory has the following entries: .. c:member:: virtual_address Relative virtual address (RVA) of the PE data directory. If this is zero, then the data directory is missing. Note that for digital signature, this is the file offset, not RVA. .. c:member:: size Size of the PE data directory, in bytes. The index for the data directory entry can be one of the following values: .. c:type:: IMAGE_DIRECTORY_ENTRY_EXPORT Data directory for exported functions. .. c:type:: IMAGE_DIRECTORY_ENTRY_IMPORT Data directory for import directory. .. c:type:: IMAGE_DIRECTORY_ENTRY_RESOURCE Data directory for resource section. .. c:type:: IMAGE_DIRECTORY_ENTRY_EXCEPTION Data directory for exception information. .. c:type:: IMAGE_DIRECTORY_ENTRY_SECURITY This is the raw file offset and length of the image digital signature. If the image has no embedded digital signature, this directory will contain zeros. .. c:type:: IMAGE_DIRECTORY_ENTRY_BASERELOC Data directory for image relocation table. .. c:type:: IMAGE_DIRECTORY_ENTRY_DEBUG Data directory for debug information. IMAGE_DEBUG_DIRECTORY::Type values: .. c:type:: IMAGE_DEBUG_TYPE_UNKNOWN .. c:type:: IMAGE_DEBUG_TYPE_COFF .. c:type:: IMAGE_DEBUG_TYPE_CODEVIEW .. c:type:: IMAGE_DEBUG_TYPE_FPO .. c:type:: IMAGE_DEBUG_TYPE_MISC .. c:type:: IMAGE_DEBUG_TYPE_EXCEPTION .. c:type:: IMAGE_DEBUG_TYPE_FIXUP .. c:type:: IMAGE_DEBUG_TYPE_OMAP_TO_SRC .. c:type:: IMAGE_DEBUG_TYPE_OMAP_FROM_SRC .. c:type:: IMAGE_DEBUG_TYPE_BORLAND .. c:type:: IMAGE_DEBUG_TYPE_RESERVED10 .. c:type:: IMAGE_DEBUG_TYPE_CLSID .. c:type:: IMAGE_DEBUG_TYPE_VC_FEATURE .. c:type:: IMAGE_DEBUG_TYPE_POGO .. c:type:: IMAGE_DEBUG_TYPE_ILTCG .. c:type:: IMAGE_DEBUG_TYPE_MPX .. c:type:: IMAGE_DEBUG_TYPE_REPRO .. c:type:: IMAGE_DIRECTORY_ENTRY_ARCHITECTURE .. c:type:: IMAGE_DIRECTORY_ENTRY_COPYRIGHT .. c:type:: IMAGE_DIRECTORY_ENTRY_TLS Data directory for image thread local storage. .. c:type:: IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG Data directory for image load configuration. .. c:type:: IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT Data directory for image bound import table. .. c:type:: IMAGE_DIRECTORY_ENTRY_IAT Data directory for image Import Address Table. .. c:type:: IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT Data directory for Delayed Import Table. Structure of the delayed import table is linker-dependent. Microsoft version of delayed imports is described in the sources "delayimp.h" and "delayimp.cpp", which can be found in MS Visual Studio 2008 CRT sources. .. c:type:: IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR Data directory for .NET headers. *Example: pe.data_directories[pe.IMAGE_DIRECTORY_ENTRY_EXPORT].virtual_address != 0* .. c:type:: number_of_sections Number of sections in the PE. .. c:type:: sections .. versionadded:: 3.3.0 A zero-based array of section objects, one for each section the PE has. Individual sections can be accessed by using the [] operator. Each section object has the following attributes: .. c:member:: name Section name. .. c:member:: full_name If the name in the section table contains a slash (/) followed by a representation of the decimal number in ASCII format, then this field contains a string from the specified offset in the string table. Otherwise, this field contains the same value as a name field. Even though it's not a standard, MinGW and Cygwin compilers use this feature to store section names which are longer than 8 characters. .. c:member:: characteristics Section characteristics. .. c:member:: virtual_address Section virtual address. .. c:member:: virtual_size Section virtual size. .. c:member:: raw_data_offset Section raw offset. .. c:member:: raw_data_size Section raw size. .. c:member:: pointer_to_relocations .. versionadded:: 3.8.0 Value of IMAGE_SECTION_HEADER::PointerToRelocations. .. c:member:: pointer_to_line_numbers .. versionadded:: 3.8.0 Value of IMAGE_SECTION_HEADER::PointerToLinenumbers. .. c:member:: number_of_relocations .. versionadded:: 3.8.0 Value of IMAGE_SECTION_HEADER::NumberOfRelocations. .. c:member:: number_of_line_numbers .. versionadded:: 3.8.0 Value of IMAGE_SECTION_HEADER::NumberOfLineNumbers. *Example: pe.sections[0].name == ".text"* Individual section characteristics can be inspected using a bitwise AND operation with the following constants: .. c:type:: SECTION_NO_PAD .. c:type:: SECTION_CNT_CODE .. c:type:: SECTION_CNT_INITIALIZED_DATA .. c:type:: SECTION_CNT_UNINITIALIZED_DATA .. c:type:: SECTION_LNK_OTHER .. c:type:: SECTION_LNK_INFO .. c:type:: SECTION_LNK_REMOVE .. c:type:: SECTION_LNK_COMDAT .. c:type:: SECTION_NO_DEFER_SPEC_EXC .. c:type:: SECTION_GPREL .. c:type:: SECTION_MEM_FARDATA .. c:type:: SECTION_MEM_PURGEABLE .. c:type:: SECTION_MEM_16BIT .. c:type:: SECTION_LNK_NRELOC_OVFL .. c:type:: SECTION_MEM_LOCKED .. c:type:: SECTION_MEM_PRELOAD .. c:type:: SECTION_ALIGN_1BYTES .. c:type:: SECTION_ALIGN_2BYTES .. c:type:: SECTION_ALIGN_4BYTES .. c:type:: SECTION_ALIGN_8BYTES .. c:type:: SECTION_ALIGN_16BYTES .. c:type:: SECTION_ALIGN_32BYTES .. c:type:: SECTION_ALIGN_64BYTES .. c:type:: SECTION_ALIGN_128BYTES .. c:type:: SECTION_ALIGN_256BYTES .. c:type:: SECTION_ALIGN_512BYTES .. c:type:: SECTION_ALIGN_1024BYTES .. c:type:: SECTION_ALIGN_2048BYTES .. c:type:: SECTION_ALIGN_4096BYTES .. c:type:: SECTION_ALIGN_8192BYTES .. c:type:: SECTION_ALIGN_MASK .. c:type:: SECTION_MEM_DISCARDABLE .. c:type:: SECTION_MEM_NOT_CACHED .. c:type:: SECTION_MEM_NOT_PAGED .. c:type:: SECTION_MEM_SHARED .. c:type:: SECTION_MEM_EXECUTE .. c:type:: SECTION_MEM_READ .. c:type:: SECTION_MEM_WRITE .. c:type:: SECTION_SCALE_INDEX *Example: pe.sections[1].characteristics & pe.SECTION_CNT_CODE* .. c:type:: overlay .. versionadded:: 3.6.0 A structure containing the following integer members: .. c:member:: offset Overlay section offset. This is 0 for PE files that don't have overlaid data and undefined for non-PE files. .. c:member:: size Overlay section size. This is 0 for PE files that don't have overlaid data and undefined for non-PE files. *Example: uint8(pe.overlay.offset) == 0x0d and pe.overlay.size > 1024* .. c:type:: number_of_resources Number of resources in the PE. .. c:type:: resource_timestamp Resource timestamp. This is stored as an integer. .. c:type:: resource_version An object with two integer attributes, major and minor versions. .. c:member:: major Major resource version. .. c:member:: minor Minor resource version. .. c:type:: resources .. versionchanged:: 3.3.0 A zero-based array of resource objects, one for each resource the PE has. Individual resources can be accessed by using the [] operator. Each resource object has the following attributes: .. c:member:: rva The RVA of the resource data. .. c:member:: offset Offset for the resource data. This can be undefined if the RVA is invalid. .. c:member:: length Length of the resource data. .. c:member:: type Type of the resource (integer). .. c:member:: id ID of the resource (integer). .. c:member:: language Language of the resource (integer). .. c:member:: type_string Type of the resource as a string, if specified. .. c:member:: name_string Name of the resource as a string, if specified. .. c:member:: language_string Language of the resource as a string, if specified. All resources must have a type, id (name), and language specified. They can be either an integer or string, but never both, for any given level. *Example: pe.resources[0].type == pe.RESOURCE_TYPE_RCDATA* *Example: pe.resources[0].name_string == "F\\x00I\\x00L\\x00E\\x00"* Resource types can be inspected using the following constants: .. c:type:: RESOURCE_TYPE_CURSOR .. c:type:: RESOURCE_TYPE_BITMAP .. c:type:: RESOURCE_TYPE_ICON .. c:type:: RESOURCE_TYPE_MENU .. c:type:: RESOURCE_TYPE_DIALOG .. c:type:: RESOURCE_TYPE_STRING .. c:type:: RESOURCE_TYPE_FONTDIR .. c:type:: RESOURCE_TYPE_FONT .. c:type:: RESOURCE_TYPE_ACCELERATOR .. c:type:: RESOURCE_TYPE_RCDATA .. c:type:: RESOURCE_TYPE_MESSAGETABLE .. c:type:: RESOURCE_TYPE_GROUP_CURSOR .. c:type:: RESOURCE_TYPE_GROUP_ICON .. c:type:: RESOURCE_TYPE_VERSION .. c:type:: RESOURCE_TYPE_DLGINCLUDE .. c:type:: RESOURCE_TYPE_PLUGPLAY .. c:type:: RESOURCE_TYPE_VXD .. c:type:: RESOURCE_TYPE_ANICURSOR .. c:type:: RESOURCE_TYPE_ANIICON .. c:type:: RESOURCE_TYPE_HTML .. c:type:: RESOURCE_TYPE_MANIFEST For more information refer to: http://msdn.microsoft.com/en-us/library/ms648009(v=vs.85).aspx .. c:type:: version_info .. versionadded:: 3.2.0 Dictionary containing the PE's version information. Typical keys are: ``Comments`` ``CompanyName`` ``FileDescription`` ``FileVersion`` ``InternalName`` ``LegalCopyright`` ``LegalTrademarks`` ``OriginalFilename`` ``ProductName`` ``ProductVersion`` For more information refer to: http://msdn.microsoft.com/en-us/library/windows/desktop/ms646987(v=vs.85).aspx *Example: pe.version_info["CompanyName"] contains "Microsoft"* .. c:type:: version_info_list Array of structures containing information about the PE's version information. .. c:member:: key Key of version information. .. c:member:: value Value of version information. *Example: pe.version_info_list[0].value contains "Microsoft"* .. c:type:: number_of_signatures Number of authenticode signatures in the PE. .. c:type:: is_signed True if any of the PE signatures is verified. Verified here means, that the signature is formally correct: digests match, signer public key correctly verifies the encrypted digest, etc. But this doesn't mean that the signer (and thus the signature) can be trusted as there are no trust anchors involved in the verification. .. c:type:: signatures A zero-based array of signature objects, one for each authenticode signature in the PE file. Usually PE files have a single signature. .. c:member:: thumbprint .. versionadded:: 3.8.0 A string containing the thumbprint of the signature. .. c:member:: issuer A string containing information about the issuer. These are some examples:: "/C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/CN=Microsoft Code Signing PCA" "/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)10/CN=VeriSign Class 3 Code Signing 2010 CA" "/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO Code Signing CA 2" .. c:member:: subject A string containing information about the subject. .. c:member:: version Version number. .. c:member:: algorithm String representation of the algorithm used for this signature. Usually "sha1WithRSAEncryption". It depends on the X.509 and PKCS#7 implementations and possibly their versions, consider using algorithm_oid instead. .. c:member:: algorithm_oid Object ID of the algorithm used for this signature, expressed in numeric ASN.1 dot notation. The name contained in algorithm is derived from this value. The object id is expected to be stable across X.509 and PKCS#7 implementations and their versions. For example, when using the current OpenSSL-based implementation:: algorithm_oid == "1.2.840.113549.1.1.11" is functionally equivalent to:: algorithm == "sha1WithRSAEncryption" .. c:member:: serial A string containing the serial number. This is an example:: "52:00:e5:aa:25:56:fc:1a:86:ed:96:c9:d4:4b:33:c7" .. c:member:: not_before Unix timestamp on which the validity period for this signature begins. .. c:member:: not_after Unix timestamp on which the validity period for this signature ends. .. c:member:: valid_on(timestamp) Function returning true if the signature was valid on the date indicated by *timestamp*. The following sentence:: pe.signatures[n].valid_on(timestamp) Is equivalent to:: timestamp >= pe.signatures[n].not_before and timestamp <= pe.signatures[n].not_after .. c:member:: verified Boolean, true if signature was sucessfully verified. More details about what the `verified` means is mentioned under the attribute `pe.is_signed`. .. c:member:: digest_alg Name of the algorithm used for file digest. Usually "sha1" or "sha256" .. c:member:: digest Digest of the file signed in the signature. .. c:member:: file_digest Calculated digest using digest_alg of the analysed file. .. c:member:: number_of_certificates Number of the certificates stored in the signature, including the ones in countersignatures. .. c:type:: certificates A zero-based array of certificates stored in the signature, including the ones in countersignatures. The members of the certificates are identical to those already explained before, with the same name. .. c:member:: thumbprint .. c:member:: issuer .. c:member:: subject .. c:member:: version .. c:member:: algorithm .. c:member:: serial .. c:member:: not_before .. c:member:: not_after .. c:type:: signer_info Information about the signature signer. .. c:member:: program_name Optional program name stored in the signature. .. c:member:: digest Signed digest of the signature. .. c:member:: digest_alg Algorithm used for the digest of the signature. Usually "sha1" or "sha256" .. c:member:: length_of_chain Number of certificates in the signers chain. .. c:type:: chain A zero-based array of certificates in the signers chain. The members of the certificates are identical to those already explained before, with the same name. .. c:member:: thumbprint .. c:member:: issuer .. c:member:: subject .. c:member:: version .. c:member:: algorithm .. c:member:: serial .. c:member:: not_before .. c:member:: not_after .. c:member:: number_of_countersignatures Number of the countersignatures of the signature. .. c:type:: countersignatures A zero-based array of the countersignatures of the signature. Almost always it's just single timestamp one. .. c:member:: verified Boolean, true if countersignature was sucessfully verified. More details about what the `verified` means is mentioned under the attribute `pe.is_signed`. .. c:member:: sign_time Integer - unix time of the timestamp signing time. .. c:member:: digest Signed digest of the countersignature. .. c:member:: digest_alg Algorithm used for the digest of the countersignature. Usually "sha1" or "sha256" .. c:member:: length_of_chain Number of certificates in the countersigners chain. .. c:type:: chain A zero-based array of certificates in the countersigners chain. The members of the certificates are identical to those already explained before, with the same name. .. c:member:: thumbprint .. c:member:: issuer .. c:member:: subject .. c:member:: version .. c:member:: algorithm .. c:member:: serial .. c:member:: not_before .. c:member:: not_after .. c:type:: rich_signature Structure containing information about the PE's rich signature as documented `here `_. .. c:member:: offset Offset where the rich signature starts. It will be undefined if the file doesn't have a rich signature. .. c:member:: length Length of the rich signature, not including the final "Rich" marker. .. c:member:: key Key used to encrypt the data with XOR. .. c:member:: raw_data Raw data as it appears in the file. .. c:member:: clear_data Data after being decrypted by XORing it with the key. .. c:member:: version_data .. versionadded:: 4.3.0 Version fields after being decrypted by XORing it with the key. .. c:function:: version(version, [toolid]) .. versionadded:: 3.5.0 Function returning a sum of count values of all matching *version* records. Provide the optional *toolid* argument to only match when both match for one entry. More information can be found here: http://www.ntcore.com/files/richsign.htm Note: Prior to version *3.11.0*, this function returns only a boolean value (0 or 1) if the given *version* and optional *toolid* is present in an entry. *Example: pe.rich_signature.version(24215, 261) == 61* .. c:function:: toolid(toolid, [version]) .. versionadded:: 3.5.0 Function returning a sum of count values of all matching *toolid* records. Provide the optional *version* argument to only match when both match for one entry. More information can be found here: http://www.ntcore.com/files/richsign.htm Note: Prior to version *3.11.0*, this function returns only a boolean value (0 or 1) if the given *toolid* and optional *version* is present in an entry. *Example: pe.rich_signature.toolid(170, 40219) >= 99* .. c:type:: pdb_path .. versionadded:: 4.0.0 Path of the PDB file for this PE if present. *Example: pe.pdb_path == "D:\\workspace\\2018_R9_RelBld\\target\\checkout\\custprof\\Release\\custprof.pdb"* .. c:function:: exports(function_name) Function returning true if the PE exports *function_name* or false otherwise. *Example: pe.exports("CPlApplet")* .. c:function:: exports(ordinal) .. versionadded:: 3.6.0 Function returning true if the PE exports *ordinal* or false otherwise. *Example: pe.exports(72)* .. c:function:: exports(/regular_expression/) .. versionadded:: 3.7.1 Function returning true if the PE exports *regular_expression* or false otherwise. *Example: pe.exports(/^AXS@@/)* .. c:function:: exports_index(function_name) .. versionadded:: 4.0.0 Function returning the index into the export_details array where the named function is, undefined otherwise. *Example: pe.exports_index("CPlApplet")* .. c:function:: exports_index(ordinal) .. versionadded:: 4.0.0 Function returning the index into the export_details array where the exported ordinal is, undefined otherwise. *Example: pe.exports_index(72)* .. c:function:: exports_index(/regular_expression/) .. versionadded:: 4.0.0 Function returning the first index into the export_details array where the regular expression matches the exported name, undefined otherwise. *Example: pe.exports_index(/^ERS@@/)* .. c:type:: number_of_exports .. versionadded:: 3.6.0 Number of exports in the PE. .. c:type:: export_details .. versionadded:: 4.0.0 Array of structures containing information about the PE's exports. .. c:member:: offset Offset where the exported function starts. .. c:member:: name Name of the exported function. It will be undefined if the function has no name. .. c:member:: forward_name The name of the function where this export forwards to. It will be undefined if the export is not a forwarding export. .. c:member:: ordinal The ordinal of the exported function, after the ordinal base has been applied to it. .. c:type:: dll_name .. versionadded:: 4.0.0 The name of the DLL, if it exists in the export directory. .. c:type:: export_timestamp .. versionadded:: 4.0.0 The timestamp the export data was created.. .. c:type:: number_of_imports .. versionadded:: 3.6.0 Number of imported DLLs in the PE. .. c:type:: number_of_imported_functions .. versionadded:: 4.1.0 Number of imported functions in the PE. .. c:type:: number_of_delayed_imports .. versionadded:: 4.2.0 Number of delayed imported DLLs in the PE. (Number of IMAGE_DELAYLOAD_DESCRIPTOR parsed from file) .. c:type:: number_of_delay_imported_functions .. versionadded:: 4.2.0 Number of delayed imported functions in the PE. .. c:function:: imports(dll_name, function_name) Function returning true if the PE imports *function_name* from *dll_name*, or false otherwise. *dll_name* is case insensitive. *Example: pe.imports("kernel32.dll", "WriteProcessMemory")* .. c:function:: imports(dll_name) .. versionadded:: 3.5.0 .. versionchanged:: 4.0.0 Function returning the number of functions from the *dll_name*, in the PE imports. *dll_name* is case insensitive. Note: Prior to version 4.0.0, this function returned only a boolean value indicating if the given DLL name was found in the PE imports. This change is backward compatible, as any number larger than 0 also evaluates as true. *Examples: pe.imports("kernel32.dll"), pe.imports("kernel32.dll") == 10* .. c:function:: imports(dll_name, ordinal) .. versionadded:: 3.5.0 Function returning true if the PE imports *ordinal* from *dll_name*, or false otherwise. *dll_name* is case insensitive. *Example: pe.imports("WS2_32.DLL", 3)* .. c:function:: imports(dll_regexp, function_regexp) .. versionadded:: 3.8.0 .. versionchanged:: 4.0.0 Function returning the number of functions from the PE imports where a function name matches *function_regexp* and a DLL name matches *dll_regexp*. Both *dll_regexp* and *function_regexp* are case sensitive unless you use the "/i" modifier in the regexp, as shown in the example below. Note: Prior to version 4.0.0, this function returned only a boolean value indicating if matching import was found or not. This change is backward compatible, as any number larger than 0 also evaluates as true. *Example: pe.imports(/kernel32\.dll/i, /(Read|Write)ProcessMemory/) == 2* .. c:function:: imports(import_flag, dll_name, function_name) .. versionadded:: 4.2.0 Function returning true if the PE imports *function_name* from *dll_name*, or false otherwise. *dll_name* is case insensitive. *import_flag* is flag which specify type of import which should YARA search for. This value can be composed by bitwise OR these values: .. c:member:: pe.IMPORT_STANDARD Search in standard imports .. c:member:: pe.IMPORT_DELAYED Search in delayed imports .. c:member:: pe.IMPORT_ANY Search in all imports *Example: pe.imports(pe.IMPORT_DELAYED | pe.IMPORT_STANDARD, "kernel32.dll", "WriteProcessMemory")* .. c:function:: imports(import_flag, dll_name) .. versionadded:: 4.2.0 Function returning the number of functions from the *dll_name*, in the PE imports. *dll_name* is case insensitive. *Examples: pe.imports(pe.IMPORT_DELAYED, "kernel32.dll"), pe.imports("kernel32.dll") == 10* .. c:function:: imports(import_flag, dll_name, ordinal) .. versionadded:: 4.2.0 Function returning true if the PE imports *ordinal* from *dll_name*, or false otherwise. *dll_name* is case insensitive. *Example: pe.imports(pe.IMPORT_DELAYED, "WS2_32.DLL", 3)* .. c:function:: imports(import_flag, dll_regexp, function_regexp) .. versionadded:: 4.2.0 Function returning the number of functions from the PE imports where a function name matches *function_regexp* and a DLL name matches *dll_regexp*. Both *dll_regexp* and *function_regexp* are case sensitive unless you use the "/i" modifier in the regexp, as shown in the example below. *Example: pe.imports(pe.IMPORT_DELAYED, /kernel32\.dll/i, /(Read|Write)ProcessMemory/) == 2* .. c:type:: import_details .. versionadded:: 4.2.0 Array of structures containing information about the PE's imports libraries. .. c:member:: library_name Library name. .. c:member:: number_of_functions Number of imported function. .. c:member:: functions Array of structures containing information about the PE's imports functions. .. c:member:: name Name of imported function .. c:member:: ordinal Ordinal of imported function. If ordinal does not exist this value is YR_UNDEFINED .. c:member:: rva .. versionadded:: 4.3.0 Relative virtual address (RVA) of imported function. If rva not found then this value is YR_UNDEFINED *Example: pe.import_details[1].library_name == "library_name" .. c:type:: delayed_import_details .. versionadded:: 4.2.0 Array of structures containing information about the PE's delayed imports libraries. .. c:member:: library_name Library name. .. c:member:: number_of_functions Number of imported function. .. c:member:: functions Array of structures containing information about the PE's imports functions. .. c:member:: name Name of imported function .. c:member:: ordinal Ordinal of imported function. If ordinal does not exist this value is YR_UNDEFINED .. c:member:: rva .. versionadded:: 4.3.0 Relative virtual address (RVA) of imported function. If rva not found then this value is YR_UNDEFINED *Example: pe.delayed_import_details[1].name == "library_name" .. c:function:: import_rva(dll, function) .. versionadded:: 4.3.0 Function returning the RVA of an import that matches the DLL name and function name. *Example: pe.import_rva("PtImageRW.dll", "ord4") == 254924 .. c:function:: import_rva(dll, ordinal) .. versionadded:: 4.3.0 Function returning the RVA of an import that matches the DLL name and ordinal number. *Example: pe.import_rva("PtPDF417Decode.dll", 4) == 254924 .. c:function:: delayed_import_rva(dll, function) .. versionadded:: 4.3.0 Function returning the RVA of a delayed import that matches the DLL name and function name. *Example: pe.delayed_import_rva("QDB.dll", "ord116") == 6110705 .. c:function:: delayed_import_rva(dll, ordinal) .. versionadded:: 4.3.0 Function returning the RVA of a delayed import that matches the DLL name and ordinal number. *Example: pe.delayed_import_rva("QDB.dll", 116) == 6110705 .. c:function:: locale(locale_identifier) .. versionadded:: 3.2.0 Function returning true if the PE has a resource with the specified locale identifier. Locale identifiers are 16-bit integers and can be found here: http://msdn.microsoft.com/en-us/library/windows/desktop/dd318693(v=vs.85).aspx *Example: pe.locale(0x0419) // Russian (RU)* .. c:function:: language(language_identifier) .. versionadded:: 3.2.0 Function returning true if the PE has a resource with the specified language identifier. Language identifiers are 8-bit integers and can be found here: http://msdn.microsoft.com/en-us/library/windows/desktop/dd318693(v=vs.85).aspx *Example: pe.language(0x0A) // Spanish* .. c:function:: imphash() .. versionadded:: 3.2.0 Function returning the import hash or imphash for the PE. The imphash is an MD5 hash of the PE's import table after some normalization. The imphash for a PE can be also computed with `pefile `_ and you can find more information in `Mandiant's blog `_. The returned hash string is always in lowercase. *Example: pe.imphash() == "b8bb385806b89680e13fc0cf24f4431e"* .. c:function:: section_index(name) Function returning the index into the sections array for the section that has *name*. *name* is case sensitive. *Example: pe.section_index(".TEXT")* .. c:function:: section_index(addr) .. versionadded:: 3.3.0 Function returning the index into the sections array for the section that has *addr*. *addr* can be an offset into the file or a memory address. *Example: pe.section_index(pe.entry_point)* .. c:type:: is_pe .. versionadded:: 3.8.0 Return true if the file is a PE. *Example: pe.is_pe* .. c:function:: is_dll() .. versionadded:: 3.5.0 Function returning true if the PE is a DLL. *Example: pe.is_dll()* .. c:function:: is_32bit() .. versionadded:: 3.5.0 Function returning true if the PE is 32bits. *Example: pe.is_32bit()* .. c:function:: is_64bit() .. versionadded:: 3.5.0 Function returning true if the PE is 64bits. *Example: pe.is_64bit()* .. c:function:: rva_to_offset(addr) .. versionadded:: 3.6.0 Function returning the file offset for RVA *addr*. Be careful to pass relative addresses here and not absolute addresses, like `pe.entry_point` when scanning a process. *Example: pe.rva_to_offset(pe.sections[0].virtual_address) == pe.sections[0].raw_data_offset* This example will make sure the offset for the virtual address in the first section equals the file offset for that section. yara-4.5.3/docs/modules/string.rst000066400000000000000000000024701501365277300171330ustar00rootroot00000000000000 .. _string-module: ########### String module ########### .. versionadded:: 4.3.0 The String module provides functions for manipulating strings as returned by modules. The strings referenced here are not YARA strings as defined in the strings section of your rule. .. c:function:: to_int(string) .. versionadded:: 4.3.0 Convert the given string to a signed integer. If the string starts with "0x" it is treated as base 16. If the string starts with "0" it is treated base 8. Leading '+' or '-' is also supported. *Example: string.to_int("1234") == 1234* *Example: string.to_int("-10") == -10* *Example: string.to_int("-010") == -8* .. c:function:: to_int(string, base) .. versionadded:: 4.3.0 Convert the given string, interpreted with the given base, to a signed integer. Base must be 0 or between 2 and 36 inclusive. If it is zero then the string will be intrepreted as base 16 if it starts with "0x" or as base 8 if it starts with "0". Leading '+' or '-' is also supported. *Example: string.to_int("011", 8) == 9* *Example: string.to_int("-011", 0) == -9* .. c:function:: length(string) .. versionadded:: 4.3.0 Return the length of the string, which can be any sequence of bytes. NULL bytes included. *Example: string.length("AXS\x00ERS") == 7* yara-4.5.3/docs/modules/time.rst000066400000000000000000000004731501365277300165640ustar00rootroot00000000000000 .. _time-module: ############ Time module ############ .. versionadded:: 3.7.0 The Time module allows you to use temporal conditions in your YARA rules. .. c:function:: now() Function returning an integer which is the number of seconds since January 1, 1970. *Example: pe.timestamp > time.now()* yara-4.5.3/docs/requirements.txt000066400000000000000000000000271501365277300167030ustar00rootroot00000000000000sphinx-rtd-theme==2.0.0yara-4.5.3/docs/writingmodules.rst000066400000000000000000000767451501365277300172510ustar00rootroot00000000000000.. _writing-modules: ************************ Writing your own modules ************************ For the first time ever, in YARA 3.0 you can extend its features to express more complex and refined conditions. YARA 3.0 does this by employing modules, which you can use to define data structures and functions, which can be later used from within your rules. You can see some examples of what a module can do in the :ref:`using-modules` section. The purpose of the following sections is to teach you how to create your own modules for giving YARA that cool feature you always dreamed of. The "Hello World!" module ========================= Modules are written in C and built into YARA as part of the compiling process. In order to create your own modules you must be familiar with the C programming language and how to configure and build YARA from source code. You don't need to understand how YARA does its magic; YARA exposes a simple API for modules, which is all you need to know. The source code for your module must reside in the *libyara/modules* directory of the source tree. It's recommended to use the module name as the file name for the source file, if your module's name is *foo* its source file should be *foo.c*. In the *libyara/modules* directory you'll find a *demo.c* file we'll use as our starting point. The file looks like this: .. code-block:: c #include #define MODULE_NAME demo begin_declarations; declare_string("greeting"); end_declarations; int module_initialize( YR_MODULE* module) { return ERROR_SUCCESS; } int module_finalize( YR_MODULE* module) { return ERROR_SUCCESS; } int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { yr_set_string("Hello World!", module_object, "greeting"); return ERROR_SUCCESS; } int module_unload( YR_OBJECT* module_object) { return ERROR_SUCCESS; } #undef MODULE_NAME Let's start dissecting the source code so you can understand every detail. The first line in the code is: .. code-block:: c #include The *modules.h* header file is where the definitions for YARA's module API reside, therefore this include directive is required in all your modules. The second line is: .. code-block:: c #define MODULE_NAME demo This is how you define the name of your module and is also required. Every module must define its name at the start of the source code. Module names must be unique among the modules built into YARA. Then follows the declaration section: .. code-block:: c begin_declarations; declare_string("greeting"); end_declarations; Here is where the module declares the functions and data structures that will be available for your YARA rules. In this case we are declaring just a string variable named *greeting*. We are going to discuss these concepts in greater detail in the :ref:`declaration-section`. After the declaration section you'll find a pair of functions: .. code-block:: c int module_initialize( YR_MODULE* module) { return ERROR_SUCCESS; } int module_finalize( YR_MODULE* module) { return ERROR_SUCCESS; } The ``module_initialize`` function is called during YARA's initialization while its counterpart ``module_finalize`` is called while finalizing YARA. These functions allow you to initialize and finalize any global data structure you may need to use in your module. Then comes the ``module_load`` function: .. code-block:: c int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { set_string("Hello World!", module_object, "greeting"); return ERROR_SUCCESS; } This function is invoked once for each scanned file, but only if the module is imported by some rule with the ``import`` directive. The ``module_load`` function is where your module has the opportunity to inspect the file being scanned, parse or analyze it in the way preferred, and then populate the data structures defined in the declarations section. In this example the ``module_load`` function doesn't inspect the file content at all, it just assigns the string, "Hello World!" to the variable *greeting* declared before. And finally, we have the ``module_unload`` function: .. code-block:: c int module_unload( YR_OBJECT* module_object) { return ERROR_SUCCESS; } For each call to ``module_load`` there is a corresponding call to ``module_unload``. This function allows your module to free any resource allocated during ``module_load``. There's nothing to free in this case, so the function just returns ``ERROR_SUCCESS``. Both ``module_load`` and ``module_unload`` should return ``ERROR_SUCCESS`` to indicate that everything went fine. If a different value is returned the scanning will be aborted and an error reported to the user. Building our "Hello World!" --------------------------- Modules are not magically built into YARA just by dropping their source code into the *libyara/modules* directory, you must follow two further steps in order to get them to work. The first step is adding your module to the *module_list* file also found in the *libyara/modules* directory. The *module_list* file looks like this:: MODULE(tests) MODULE(pe) #ifdef CUCKOO_MODULE MODULE(cuckoo) #endif You must add a line *MODULE()* with the name of your module to this file. In our case the resulting *module_list* is:: MODULE(tests) MODULE(pe) #ifdef CUCKOO_MODULE MODULE(cuckoo) #endif MODULE(demo) The second step is modifying the *Makefile.am* to tell the *make* program that the source code for your module must be compiled and linked into YARA. At the very beginning of *Makefile.am* you'll find this:: MODULES = libyara/modules/tests/tests.c MODULES += libyara/modules/pe/pe.c if CUCKOO_MODULE MODULES += libyara/modules/cuckoo/cuckoo.c endif Just add a new line for your module:: MODULES = libyara/modules/tests/tests.c MODULES += libyara/modules/pe/pe.c if CUCKOO_MODULE MODULES += libyara/modules/cuckoo/cuckoo.c endif MODULES += libyara/modules/demo/demo.c And that's all! Now you're ready to build YARA with your brand-new module included. Just go to the source tree root directory and type as always:: ./bootstrap.sh ./configure make sudo make install Now you should be able to create a rule like this: .. code-block:: yara import "demo" rule HelloWorld { condition: demo.greeting == "Hello World!" } Any file scanned with this rule will match the ``HelloWord`` because ``demo.greeting == "Hello World!"`` is always true. .. _declaration-section: The declaration section ======================= The declaration section is where you declare the variables, structures and functions that will be available for your YARA rules. Every module must contain a declaration section like this:: begin_declarations; end_declarations; Basic types ----------- Within the declaration section you can use ``declare_string()``, ``declare_integer()`` and ``declare_float()`` to declare string, integer, or float variables respectively. For example:: begin_declarations; declare_integer("foo"); declare_string("bar"); declare_float("baz"); end_declarations; .. note:: Floating-point variables require YARA version 3.3.0 or later. Variable names can't contain characters other than letters, numbers and underscores. These variables can be used later in your rules at any place where an integer or string is expected. Supposing your module name is "mymodule", they can be used like this:: mymodule.foo > 5 mymodule.bar matches /someregexp/ Structures ---------- Your declarations can be organized in a more structured way:: begin_declarations; declare_integer("foo"); declare_string("bar"); declare_float("baz"); begin_struct("some_structure"); declare_integer("foo"); begin_struct("nested_structure"); declare_integer("bar"); end_struct("nested_structure"); end_struct("some_structure"); begin_struct("another_structure"); declare_integer("foo"); declare_string("bar"); declare_string("baz"); declare_float("tux"); end_struct("another_structure"); end_declarations; In this example we're using ``begin_struct()`` and ``end_struct()`` to delimit two structures named *some_structure* and *another_structure*. Within the structure delimiters you can put any other declarations you want, including another structure declaration. Also notice that members of different structures can have the same name, but members within the same structure must have unique names. When referring to these variables from your rules it would be like this:: mymodule.foo mymodule.some_structure.foo mymodule.some_structure.nested_structure.bar mymodule.another_structure.baz Arrays ------ In the same way you declare individual strings, integers, floats or structures, you can declare arrays of them:: begin_declarations; declare_integer_array("foo"); declare_string_array("bar"); declare_float_array("baz"); begin_struct_array("struct_array"); declare_integer("foo"); declare_string("bar"); end_struct_array("struct_array"); end_declarations; Individual values in the array are referenced like in most programming languages:: foo[0] bar[1] baz[3] struct_array[4].foo struct_array[1].bar Arrays are zero-based and don't have a fixed size, they will grow as needed when you start initializing its values. Dictionaries ------------ .. versionadded:: 3.2.0 You can also declare dictionaries of integers, floats, strings, or structures:: begin_declarations; declare_integer_dictionary("foo"); declare_string_dictionary("bar"); declare_float_dictionary("baz") begin_struct_dictionary("struct_dict"); declare_integer("foo"); declare_string("bar"); end_struct_dictionary("struct_dict"); end_declarations; Individual values in the dictionary are accessed by using a string key:: foo["somekey"] bar["anotherkey"] baz["yetanotherkey"] struct_dict["k1"].foo struct_dict["k1"].bar .. _declaring-functions: Functions --------- One of the more powerful features of YARA modules is the possibility of declaring functions that can be later invoked from your rules. Functions must appear in the declaration section in this way:: declare_function(, , , ); ** is the name that will be used in your YARA rules to invoke the function. ** is a string containing one character per function argument, where the character indicates the type of the argument. Functions can receive four different types of arguments: string, integer, float and regular expression, denoted by characters: **s**, **i**, **f** and **r** respectively. If your function receives two integers ** must be *"ii"*, if it receives an integer as the first argument and a string as the second one ** must be *"is"*, if it receives three strings and a float ** must be "*sssf*". ** is a string with a single character indicating the return type. Possible return types are string (*"s"*) integer (*"i"*) and float (*"f"*). ** is the identifier for the actual implementation of your function. Here you have a full example: .. code-block:: c define_function(isum) { int64_t a = integer_argument(1); int64_t b = integer_argument(2); return_integer(a + b); } define_function(fsum) { double a = float_argument(1); double b = float_argument(2); return_integer(a + b); } begin_declarations; declare_function("sum", "ii", "i", sum); end_declarations; As you can see in the example above, your function code must be defined before the declaration section, like this:: define_function() { ...your code here } Functions can be overloaded as in C++ and other programming languages. You can declare two functions with the same name as long as they differ in the type or number of arguments. One example of overloaded functions can be found in the :ref:`hash-module`, it has two functions for calculating MD5 hashes, one receiving an offset and length within the file and another one receiving a string:: begin_declarations; declare_function("md5", "ii", "s", data_md5); declare_function("md5", "s", "s", string_md5); end_declarations; We are going to discuss function implementation more in depth in the :ref:`implementing-functions` section. Initialization and finalization =============================== Every module must implement two functions for initialization and finalization: ``module_initialize`` and ``module_finalize``. The former is called during YARA's initialization by :c:func:`yr_initialize` while the latter is called during finalization by :c:func:`yr_finalize`. Both functions are invoked whether or not the module is being imported by some rule. These functions give your module an opportunity to initialize any global data structure it may need, but most of the time they are just empty functions: .. code-block:: c int module_initialize( YR_MODULE* module) { return ERROR_SUCCESS; } int module_finalize( YR_MODULE* module) { return ERROR_SUCCESS; } Any returned value different from ``ERROR_SUCCESS`` will abort YARA's execution. Implementing the module's logic =============================== Besides ``module_initialize`` and ``module_finalize`` every module must implement two other functions which are called by YARA during the scanning of a file or process memory space: ``module_load`` and ``module_unload``. Both functions are called once for each scanned file or process, but only if the module was imported by means of the ``import`` directive. If the module is not imported by some rule neither ``module_load`` nor ``module_unload`` will be called. The ``module_load`` function has the following prototype: .. code-block:: c int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) The ``context`` argument contains information relative to the current scan, including the data being scanned. The ``module_object`` argument is a pointer to a ``YR_OBJECT`` structure associated with the module. Each structure, variable or function declared in a YARA module is represented by a ``YR_OBJECT`` structure. These structures form a tree whose root is the module's ``YR_OBJECT`` structure. If you have the following declarations in a module named *mymodule*:: begin_declarations; declare_integer("foo"); begin_struct("bar"); declare_string("baz"); end_struct("bar"); end_declarations; Then the tree will look like this:: YR_OBJECT(type=OBJECT_TYPE_STRUCT, name="mymodule") | |_ YR_OBJECT(type=OBJECT_TYPE_INTEGER, name="foo") | |_ YR_OBJECT(type=OBJECT_TYPE_STRUCT, name="bar") | |_ YR_OBJECT(type=OBJECT_TYPE_STRING, name="baz") Notice that both *bar* and *mymodule* are of the same type ``OBJECT_TYPE_STRUCT``, which means that the ``YR_OBJECT`` associated with the module is just another structure like *bar*. In fact, when you write in your rules something like ``mymodule.foo`` you're performing a field lookup in a structure in the same way that ``bar.baz`` does. In summary, the ``module_object`` argument allows you to access every variable, structure or function declared by the module by providing a pointer to the root of the objects tree. The ``module_data`` argument is a pointer to any additional data passed to the module, and ``module_data_size`` is the size of that data. Not all modules require additional data, most of them rely on the data being scanned alone, but a few of them require more information as input. The :ref:`cuckoo-module` is a good example of this, it receives a behavior report associated with PE files being scanned which is passed in the ``module_data`` and ``module_data_size`` arguments. For more information on how to pass additional data to your module take a look at the ``-x`` argument in :ref:`command-line`. .. _accessing-scanned-data: Accessing the scanned data -------------------------- Most YARA modules need to access the file or process memory being scanned to extract information from it. The data being scanned is sent to the module in the ``YR_SCAN_CONTEXT`` structure passed to the ``module_load`` function. The data is sometimes sliced in blocks, therefore your module needs to iterate over the blocks by using the ``foreach_memory_block`` macro: .. code-block:: c int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { YR_MEMORY_BLOCK* block; foreach_memory_block(context, block) { ..do something with the current memory block } } Each memory block is represented by a ``YR_MEMORY_BLOCK`` structure with the following attributes: .. c:type:: YR_MEMORY_BLOCK_FETCH_DATA_FUNC fetch_data Pointer to a function returning a pointer to the block's data. .. c:type:: size_t size Size of the data block. .. c:type:: size_t base Base offset/address for this block. If a file is being scanned this field contains the offset within the file where the block begins, if a process memory space is being scanned this contains the virtual address where the block begins. The blocks are always iterated in the same order as they appear in the file or process memory. In the case of files the first block will contain the beginning of the file. Actually, a single block will contain the whole file's content in most cases, but you can't rely on that while writing your code. For very big files YARA could eventually split the file into two or more blocks, and your module should be prepared to handle that. The story is very different for processes. While scanning a process memory space your module will definitely receive a large number of blocks, one for each committed memory region in the process address space. However, there are some cases where you don't actually need to iterate over the blocks. If your module just parses the header of some file format you can safely assume that the whole header is contained within the first block (put some checks in your code nevertheless). In those cases you can use the ``first_memory_block`` macro: .. code-block:: c int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { YR_MEMORY_BLOCK* block; const uint8_t* block_data; block = first_memory_block(context); if (block != NULL) { block_data = yr_fetch_block_data(block) if (block_data != NULL) { ..do something with the memory block } } } In the previous example you can also see how to use the ``yr_fetch_block_data`` function. This function receives a pointer to the same block (as a ``self`` or ``this`` pointer) and returns a pointer to the block's data. Your module doesn't own the memory pointed to by this pointer, freeing that memory is not your responsibility. However keep in mind that the pointer is valid only until you ask for the next memory block. As long as you use the pointer within the scope of a ``foreach_memory_block`` you are on the safe side. Also take into account that ``yr_fetch_block_data`` can return a NULL pointer, your code must be prepared for that case. .. code-block:: c const uint8_t* block_data; foreach_memory_block(context, block) { block_data = yr_fetch_block_data(block); if (block_data != NULL) { // using block_data is safe here. } } // the memory pointed to by block_data can be already freed here. Setting variable's values ------------------------- The ``module_load`` function is where you assign values to the variables declared in the declarations section, once you've parsed or analyzed the scanned data and/or any additional module's data. This is done by using the ``set_float``, ``set_integer``, and ``set_string`` functions: .. c:function:: void set_float(double value, YR_OBJECT* object, const char* field, ...) .. c:function:: void set_integer(int64_t value, YR_OBJECT* object, const char* field, ...) .. c:function:: void set_string(const char* value, YR_OBJECT* object, const char* field, ...) These functions receive a value to be assigned to the variable, a pointer to a ``YR_OBJECT`` representing the variable itself or some ancestor of that variable, a field descriptor, and additional arguments as defined by the field descriptor. If we are assigning the value to the variable represented by ``object`` itself, then the field descriptor must be ``NULL``. For example, assuming that ``object`` points to a ``YR_OBJECT`` structure corresponding to some integer variable, we can set the value for that integer variable with: .. code-block:: c set_integer(, object, NULL); The field descriptor is used when you want to assign the value to some descendant of ``object``. For example, consider the following declarations:: begin_declarations; begin_struct("foo"); declare_string("bar"); begin_struct("baz"); declare_integer("qux"); end_struct("baz"); end_struct("foo"); end_declarations; If ``object`` points to the ``YR_OBJECT`` associated with the ``foo`` structure you can set the value for the ``bar`` string like this: .. code-block:: c set_string(, object, "bar"); And the value for ``qux`` like this: .. code-block:: c set_integer(, object, "baz.qux"); Do you remember that the ``module_object`` argument for ``module_load`` was a pointer to a ``YR_OBJECT``? Do you remember that this ``YR_OBJECT`` is a structure just like ``foo`` is? Well, you could also set the values for ``bar`` and ``qux`` like this: .. code-block:: c set_string(, module_object, "foo.bar"); set_integer(, module_object, "foo.baz.qux"); But what happens with arrays? How can I set the value for array items? If you have the following declarations:: begin_declarations; declare_integer_array("foo"); begin_struct_array("bar") declare_string("baz"); declare_integer_array("qux"); end_struct_array("bar"); end_declarations; Then the following statements are all valid: .. code-block:: c set_integer(, module, "foo[0]"); set_integer(, module, "foo[%i]", 2); set_string(, module, "bar[%i].baz", 5); set_string(, module, "bar[0].qux[0]"); set_string(, module, "bar[0].qux[%i]", 0); set_string(, module, "bar[%i].qux[%i]", 100, 200); Those ``%i`` in the field descriptor are replaced by the additional integer arguments passed to the function. This works in the same way as ``printf`` in C programs, but the only format specifiers accepted are ``%i`` and ``%s``, for integer and string arguments respectively. The ``%s`` format specifier is used for assigning values to a certain key in a dictionary: .. code-block:: c set_integer(, module, "foo[\"key\"]"); set_integer(, module, "foo[%s]", "key"); set_string(, module, "bar[%s].baz", "another_key"); If you don't explicitly assign a value to a declared variable, array or dictionary item it will remain in an undefined state. That's not a problem at all, and is even useful in many cases. For example, if your module parses files from a certain format and it receives one from a different format, you can safely leave all your variables undefined instead of assigning them bogus values that don't make sense. YARA will handle undefined values in rule conditions as described in :ref:`using-modules`. In addition to the ``set_float``, ``set_integer``, and ``set_string`` functions, you have their ``get_float``, ``get_integer``, and ``get_string`` counterparts. As the names suggest, they are used for getting the value of a variable, which can be useful in the implementation of your functions to retrieve values previously stored by ``module_load``. .. c:function:: double get_float(YR_OBJECT* object, const char* field, ...) .. c:function:: int64_t get_integer(YR_OBJECT* object, const char* field, ...) .. c:function:: SIZED_STRING* get_string(YR_OBJECT* object, const char* field, ...) There's also a function to get any ``YR_OBJECT`` in the objects tree: .. c:function:: YR_OBJECT* get_object(YR_OBJECT* object, const char* field, ...) Here is a little exam... Are the following two lines equivalent? Why? .. code-block:: c set_integer(1, get_object(module_object, "foo.bar"), NULL); set_integer(1, module_object, "foo.bar"); .. _storing-data-for-later-use: Storing data for later use -------------------------- Sometimes the information stored directly in your variables by means of ``set_integer`` and ``set_string`` is not enough. You may need to store more complex data structures or information that doesn't need to be exposed to YARA rules. Storing information is essential when your module exports functions to be used in YARA rules. The implementation of these functions usually require to access information generated by ``module_load`` which must kept somewhere. You may be tempted to define global variables to store the required information, but this would make your code non-thread-safe. The correct approach is using the ``data`` field of the ``YR_OBJECT`` structures. Each ``YR_OBJECT`` has a ``void* data`` field which can be safely used by your code to store a pointer to any data you may need. A typical pattern is using the ``data`` field of the module's ``YR_OBJECT``, like in the following example: .. code-block:: c typedef struct _MY_DATA { int some_integer; } MY_DATA; int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { module_object->data = yr_malloc(sizeof(MY_DATA)); ((MY_DATA*) module_object->data)->some_integer = 0; return ERROR_SUCCESS; } Don't forget to release the allocated memory in the ``module_unload`` function: .. code-block:: cpp int module_unload( YR_OBJECT* module_object) { yr_free(module_object->data); return ERROR_SUCCESS; } .. warning:: Don't use global variables for storing data. Functions in a module can be invoked from different threads at the same time and data corruption or misbehavior can occur. .. _implementing-functions: More about functions ==================== We already showed how to declare a function in :ref:`The declaration section `. Here we are going to discuss how to provide an implementation for them. Function arguments ------------------ Within the function's code you get its arguments by using ``integer_argument(n)``, ``float_argument(n)``, ``regexp_argument(n)``, ``string_argument(n)`` or ``sized_string_argument(n)`` depending on the type of the argument, where *n* is the 1-based argument's number. ``string_argument(n)`` can be used when your function expects to receive a NULL-terminated C string, if your function can receive arbitrary binary data possibly containing NULL characters you must use ``sized_string_argument(n)``. Here you have some examples: .. code-block:: c int64_t arg_1 = integer_argument(1); RE* arg_2 = regexp_argument(2); char* arg_3 = string_argument(3); SIZED_STRING* arg_4 = sized_string_argument(4); double arg_5 = float_argument(1); The C type for integer arguments is ``int64_t``, for float arguments is ``double``, for regular expressions is ``RE*``, for NULL-terminated strings is ``char*`` and for strings possibly containing NULL characters is ``SIZED_STRING*``. ``SIZED_STRING`` structures have the following attributes: .. c:type:: SIZED_STRING .. c:member:: length String's length. .. c:member:: c_string ``char*`` pointing to the string content. Return values ------------- Functions can return three types of values: strings, integers and floats. Instead of using the C *return* statement you must use ``return_string(x)``, ``return_integer(x)`` or ``return_float(x)`` to return from a function, depending on the function's return type. In all cases *x* is a constant, variable, or expression evaluating to ``char*``, ``int64_t`` or ``double`` respectively. You can use ``return_string(YR_UNDEFINED)``, ``return_float(YR_UNDEFINED)`` and ``return_integer(YR_UNDEFINED)`` to return undefined values from the function. This is useful in many situations, for example if the arguments passed to the functions don't make sense, or if your module expects a particular file format and the scanned file is from another format, or in any other case where your function can't a return a valid value. .. warning:: Don't use the C *return* statement for returning from a function. The returned value will be interpreted as an error code. Accessing objects ----------------- While writing a function we sometimes need to access values previously assigned to the module's variables, or additional data stored in the ``data`` field of ``YR_OBJECT`` structures as discussed earlier in :ref:`storing-data-for-later-use`. But for that we need a way to get access to the corresponding ``YR_OBJECT`` first. There are two functions to do that: ``yr_module()`` and ``yr_parent()``. The ``yr_module()`` function returns a pointer to the top-level ``YR_OBJECT`` corresponding to the module, the same one passed to the ``module_load`` function. The ``yr_parent()`` function returns a pointer to the ``YR_OBJECT`` corresponding to the structure where the function is contained. For example, consider the following code snippet: .. code-block:: c define_function(f1) { YR_OBJECT* module = yr_module(); YR_OBJECT* parent = yr_parent(); // parent == module; } define_function(f2) { YR_OBJECT* module = yr_module(); YR_OBJECT* parent = yr_parent(); // parent != module; } begin_declarations; declare_function("f1", "i", "i", f1); begin_struct("foo"); declare_function("f2", "i", "i", f2); end_struct("foo"); end_declarations; In ``f1`` the ``module`` variable points to the top-level ``YR_OBJECT`` as well as the ``parent`` variable, because the parent for ``f1`` is the module itself. In ``f2`` however the ``parent`` variable points to the ``YR_OBJECT`` corresponding to the ``foo`` structure while ``module`` points to the top-level ``YR_OBJECT`` as before. Scan context ------------ From within a function you can also access the ``YR_SCAN_CONTEXT`` structure discussed earlier in :ref:`accessing-scanned-data`. This is useful for functions which needs to inspect the file or process memory being scanned. This is how you get a pointer to the ``YR_SCAN_CONTEXT`` structure: .. code-block:: c YR_SCAN_CONTEXT* context = yr_scan_context(); yara-4.5.3/docs/writingrules.rst000066400000000000000000001621421501365277300167160ustar00rootroot00000000000000******************* Writing YARA rules ******************* YARA rules are easy to write and understand, and they have a syntax that resembles the C language. Here is the simplest rule that you can write for YARA, which does absolutely nothing: .. code-block:: yara rule dummy { condition: false } Each rule in YARA starts with the keyword ``rule`` followed by a rule identifier. Identifiers must follow the same lexical conventions of the C programming language, they can contain any alphanumeric character and the underscore character, but the first character cannot be a digit. Rule identifiers are case sensitive and cannot exceed 128 characters. The following keywords are reserved and cannot be used as an identifier: .. list-table:: YARA keywords :widths: 10 10 10 10 10 10 10 10 * - all - and - any - ascii - at - base64 - base64wide - condition * - contains - endswith - entrypoint - false - filesize - for - fullword - global * - import - icontains - iendswith - iequals - in - include - int16 - int16be * - int32 - int32be - int8 - int8be - istartswith - matches - meta - nocase * - none - not - of - or - private - rule - startswith - strings * - them - true - uint16 - uint16be - uint32 - uint32be - uint8 - uint8be * - wide - xor - defined - - - - - Rules are generally composed of two sections: strings definition and condition. The strings definition section can be omitted if the rule doesn't rely on any string, but the condition section is always required. The strings definition section is where the strings that will be part of the rule are defined. Each string has an identifier consisting of a $ character followed by a sequence of alphanumeric characters and underscores, these identifiers can be used in the condition section to refer to the corresponding string. Strings can be defined in text or hexadecimal form, as shown in the following example: .. code-block:: yara rule ExampleRule { strings: $my_text_string = "text here" $my_hex_string = { E2 34 A1 C8 23 FB } condition: $my_text_string or $my_hex_string } Text strings are enclosed in double quotes just like in the C language. Hex strings are enclosed by curly brackets, and they are composed by a sequence of hexadecimal numbers that can appear contiguously or separated by spaces. Decimal numbers are not allowed in hex strings. The condition section is where the logic of the rule resides. This section must contain a boolean expression telling under which circumstances a file or process satisfies the rule or not. Generally, the condition will refer to previously defined strings by using their identifiers. In this context the string identifier acts as a boolean variable which evaluate to true if the string was found in the file or process memory, or false if otherwise. Comments ======== You can add comments to your YARA rules just as if it was a C source file, both single-line and multi-line C-style comments are supported. .. code-block:: yara /* This is a multi-line comment ... */ rule CommentExample // ... and this is single-line comment { condition: false // just a dummy rule, don't do this } Strings ======= There are three types of strings in YARA: hexadecimal strings, text strings and regular expressions. Hexadecimal strings are used for defining raw sequences of bytes, while text strings and regular expressions are useful for defining portions of legible text. However text strings and regular expressions can be also used for representing raw bytes by mean of escape sequences as will be shown below. Hexadecimal strings ------------------- Hexadecimal strings allow four special constructions that make them more flexible: wild-cards, not operators, jumps, and alternatives. Wild-cards are just placeholders that you can put into the string indicating that some bytes are unknown and they should match anything. The placeholder character is the question mark (?). Here you have an example of a hexadecimal string with wild-cards: .. code-block:: yara rule WildcardExample { strings: $hex_string = { E2 34 ?? C8 A? FB } condition: $hex_string } As shown in the example the wild-cards are nibble-wise, which means that you can define just one nibble of the byte and leave the other unknown. Starting with version 4.3.0, you may specify that a byte is not a specific value. For that you can use the not operator with a byte value: .. code-block:: yara rule NotExample { strings: $hex_string = { F4 23 ~00 62 B4 } $hex_string2 = { F4 23 ~?0 62 B4 } condition: $hex_string and $hex_string2 } In the example above we have a byte prefixed with a tilde (~), which is the not operator. This defines that the byte in that location can take any value except the value specified. In this case the first string will only match if the byte is not 00. The not operator can also be used with nibble-wise wild-cards, so the second string will only match if the second nibble is not zero. Wild-cards and not operators are useful when defining strings whose content can vary but you know the length of the variable chunks, however, this is not always the case. In some circumstances you may need to define strings with chunks of variable content and length. In those situations you can use jumps instead of wild-cards: .. code-block:: yara rule JumpExample { strings: $hex_string = { F4 23 [4-6] 62 B4 } condition: $hex_string } In the example above we have a pair of numbers enclosed in square brackets and separated by a hyphen, that's a jump. This jump is indicating that any arbitrary sequence from 4 to 6 bytes can occupy the position of the jump. Any of the following strings will match the pattern:: F4 23 01 02 03 04 62 B4 F4 23 00 00 00 00 00 62 B4 F4 23 15 82 A3 04 45 22 62 B4 Any jump [X-Y] must meet the condition 0 <= X <= Y. In previous versions of YARA both X and Y must be lower than 256, but starting with YARA 2.0 there is no limit for X and Y. These are valid jumps:: FE 39 45 [0-8] 89 00 FE 39 45 [23-45] 89 00 FE 39 45 [1000-2000] 89 00 This is invalid:: FE 39 45 [10-7] 89 00 If the lower and higher bounds are equal you can write a single number enclosed in brackets, like this:: FE 39 45 [6] 89 00 The above string is equivalent to both of these:: FE 39 45 [6-6] 89 00 FE 39 45 ?? ?? ?? ?? ?? ?? 89 00 Starting with YARA 2.0 you can also use unbounded jumps:: FE 39 45 [10-] 89 00 FE 39 45 [-] 89 00 The first one means ``[10-infinite]``, the second one means ``[0-infinite]``. There are also situations in which you may want to provide different alternatives for a given fragment of your hex string. In those situations you can use a syntax which resembles a regular expression: .. code-block:: yara rule AlternativesExample1 { strings: $hex_string = { F4 23 ( 62 B4 | 56 ) 45 } condition: $hex_string } This rule will match any file containing ``F42362B445`` or ``F4235645``. But more than two alternatives can be also expressed. In fact, there are no limits to the amount of alternative sequences you can provide, and neither to their lengths. .. code-block:: yara rule AlternativesExample2 { strings: $hex_string = { F4 23 ( 62 B4 | 56 | 45 ?? 67 ) 45 } condition: $hex_string } As can be seen also in the above example, strings containing wild-cards are allowed as part of alternative sequences. Text strings ------------ As shown in previous sections, text strings are generally defined like this: .. code-block:: yara rule TextExample { strings: $text_string = "foobar" condition: $text_string } This is the simplest case: an ASCII-encoded, case-sensitive string. However, text strings can be accompanied by some useful modifiers that alter the way in which the string will be interpreted. Those modifiers are appended at the end of the string definition separated by spaces, as will be discussed below. Text strings can also contain the following subset of the escape sequences available in the C language: .. list-table:: :widths: 3 10 * - ``\"`` - Double quote * - ``\\`` - Backslash * - ``\r`` - Carriage return * - ``\t`` - Horizontal tab * - ``\n`` - New line * - ``\xdd`` - Any byte in hexadecimal notation In all versions of YARA before 4.1.0 text strings accepted any kind of unicode characters, regardless of their encoding. Those characters were interpreted by YARA as raw bytes, and therefore the final string was actually determined by the encoding format used by your text editor. This never meant to be a feature, the original intention always was that YARA strings should be ASCII-only and YARA 4.1.0 started to raise warnings about non-ASCII characters in strings. This limitation does not apply to strings in the metadata section or comments. See more details `here `_. Case-insensitive strings ^^^^^^^^^^^^^^^^^^^^^^^^ Text strings in YARA are case-sensitive by default, however you can turn your string into case-insensitive mode by appending the modifier ``nocase`` at the end of the string definition, in the same line: .. code-block:: yara rule CaseInsensitiveTextExample { strings: $text_string = "foobar" nocase condition: $text_string } With the ``nocase`` modifier the string *foobar* will match *Foobar*, *FOOBAR*, and *fOoBaR*. This modifier can be used in conjunction with any modifier, except ``base64``, ``base64wide`` and ``xor``. Wide-character strings ^^^^^^^^^^^^^^^^^^^^^^ The ``wide`` modifier can be used to search for strings encoded with two bytes per character, something typical in many executable binaries. For example, if the string "Borland" appears encoded as two bytes per character (i.e. ``B\x00o\x00r\x00l\x00a\x00n\x00d\x00``), then the following rule will match: .. code-block:: yara rule WideCharTextExample1 { strings: $wide_string = "Borland" wide condition: $wide_string } However, keep in mind that this modifier just interleaves the ASCII codes of the characters in the string with zeroes, it does not support truly UTF-16 strings containing non-English characters. If you want to search for strings in both ASCII and wide form, you can use the ``ascii`` modifier in conjunction with ``wide`` , no matter the order in which they appear. .. code-block:: yara rule WideCharTextExample2 { strings: $wide_and_ascii_string = "Borland" wide ascii condition: $wide_and_ascii_string } The ``ascii`` modifier can appear alone, without an accompanying ``wide`` modifier, but it's not necessary to write it because in absence of ``wide`` the string is assumed to be ASCII by default. XOR strings ^^^^^^^^^^^ The ``xor`` modifier can be used to search for strings with a single byte XOR applied to them. The following rule will search for every single byte XOR applied to the string "This program cannot" (including the plaintext string): .. code-block:: yara rule XorExample1 { strings: $xor_string = "This program cannot" xor condition: $xor_string } The above rule is logically equivalent to: .. code-block:: yara rule XorExample2 { strings: $xor_string_00 = "This program cannot" $xor_string_01 = "Uihr!qsnfs`l!b`oonu" $xor_string_02 = "Vjkq\"rpmepco\"acllmv" // Repeat for every single byte XOR condition: any of them } You can also combine the ``xor`` modifier with ``fullword``, ``wide``, and ``ascii`` modifiers. For example, to search for the ``wide`` and ``ascii`` versions of a string after every single byte XOR has been applied you would use: .. code-block:: yara rule XorExample3 { strings: $xor_string = "This program cannot" xor wide ascii condition: $xor_string } The ``xor`` modifier is applied after every other modifier. This means that using the ``xor`` and ``wide`` together results in the XOR applying to the interleaved zero bytes. For example, the following two rules are logically equivalent: .. code-block:: yara rule XorExample4 { strings: $xor_string = "This program cannot" xor wide condition: $xor_string } rule XorExample4 { strings: $xor_string_00 = "T\x00h\x00i\x00s\x00 \x00p\x00r\x00o\x00g\x00r\x00a\x00m\x00 \x00c\x00a\x00n\x00n\x00o\x00t\x00" $xor_string_01 = "U\x01i\x01h\x01r\x01!\x01q\x01s\x01n\x01f\x01s\x01`\x01l\x01!\x01b\x01`\x01o\x01o\x01n\x01u\x01" $xor_string_02 = "V\x02j\x02k\x02q\x02\"\x02r\x02p\x02m\x02e\x02p\x02c\x02o\x02\"\x02a\x02c\x02l\x02l\x02m\x02v\x02" // Repeat for every single byte XOR operation. condition: any of them } Since YARA 3.11, if you want more control over the range of bytes used with the ``xor`` modifier, use: .. code-block:: yara rule XorExample5 { strings: $xor_string = "This program cannot" xor(0x01-0xff) condition: $xor_string } The above example will apply the bytes from 0x01 to 0xff, inclusively, to the string when searching. The general syntax is ``xor(minimum-maximum)``. Base64 strings ^^^^^^^^^^^^^^ The ``base64`` modifier can be used to search for strings that have been base64 encoded. A good explanation of the technique is at: https://www.leeholmes.com/searching-for-content-in-base-64-strings/ The following rule will search for the three base64 permutations of the string "This program cannot": .. code-block:: yara rule Base64Example1 { strings: $a = "This program cannot" base64 condition: $a } This will cause YARA to search for these three permutations: | VGhpcyBwcm9ncmFtIGNhbm5vd | RoaXMgcHJvZ3JhbSBjYW5ub3 | UaGlzIHByb2dyYW0gY2Fubm90 The ``base64wide`` modifier works just like the ``base64`` modifier but the results of the ``base64`` modifier are converted to wide. The interaction between ``base64`` (or ``base64wide``) and ``wide`` and ``ascii`` is as you might expect. ``wide`` and ``ascii`` are applied to the string first, and then the ``base64`` and ``base64wide`` modifiers are applied. At no point is the plaintext of the ``ascii`` or ``wide`` versions of the strings included in the search. If you want to also include those you can put them in a secondary string. The ``base64`` and ``base64wide`` modifiers also support a custom alphabet. For example: .. code-block:: yara rule Base64Example2 { strings: $a = "This program cannot" base64("!@#$%^&*(){}[].,|ABCDEFGHIJ\x09LMNOPQRSTUVWXYZabcdefghijklmnopqrstu") condition: $a } The alphabet must be 64 bytes long. The ``base64`` and ``base64wide`` modifiers are only supported with text strings. Using these modifiers with a hexadecimal string or a regular expression will cause a compiler error. Also, the ``xor``, ``fullword``, and ``nocase`` modifiers used in combination with ``base64`` or ``base64wide`` will cause a compiler error. Because of the way that YARA strips the leading and trailing characters after base64 encoding, one of the base64 encodings of "Dhis program cannow" and "This program cannot" are identical. Similarly, using the ``base64`` keyword on single ASCII characters is not recommended. For example, "a" with the ``base64`` keyword matches "\`", "b", "c", "!", "\\xA1", or "\\xE1" after base64 encoding, and will not match where the base64 encoding matches the ``[GWm2][EFGH]`` regular expression. Searching for full words ^^^^^^^^^^^^^^^^^^^^^^^^ Another modifier that can be applied to text strings is ``fullword``. This modifier guarantees that the string will match only if it appears in the file delimited by non-alphanumeric characters. For example the string *domain*, if defined as ``fullword``, doesn't match *www.mydomain.com* but it matches *www.my-domain.com* and *www.domain.com*. Regular expressions ------------------- Regular expressions are one of the most powerful features of YARA. They are defined in the same way as text strings, but enclosed in forward slashes instead of double-quotes, like in the Perl programming language. .. code-block:: yara rule RegExpExample1 { strings: $re1 = /md5: [0-9a-fA-F]{32}/ $re2 = /state: (on|off)/ condition: $re1 and $re2 } Regular expressions can be also followed by ``nocase``, ``ascii``, ``wide``, and ``fullword`` modifiers just like in text strings. The semantics of these modifiers are the same in both cases. Additionally, they can be followed by the characters ``i`` and ``s`` just after the closing slash, which is a very common convention for specifying that the regular expression is case-insensitive and that the dot (``.``) can match new-line characters. For example: .. code-block:: yara rule RegExpExample2 { strings: $re1 = /foo/i // This regexp is case-insentitive $re2 = /bar./s // In this regexp the dot matches everything, including new-line $re3 = /baz./is // Both modifiers can be used together condition: any of them } Notice that ``/foo/i`` is equivalent to ``/foo/ nocase``, but we recommend the latter when defining strings. The ``/foo/i`` syntax is useful when writing case-insensitive regular expressions for the ``matches`` operator. In previous versions of YARA, external libraries like PCRE and RE2 were used to perform regular expression matching, but starting with version 2.0 YARA uses its own regular expression engine. This new engine implements most features found in PCRE, except a few of them like capture groups, POSIX character classes ([[:isalpha:]], [[:isdigit:]], etc) and backreferences. YARA’s regular expressions recognise the following metacharacters: .. list-table:: :widths: 3 10 * - ``\`` - Quote the next metacharacter * - ``^`` - Match the beginning of the file or negates a character class when used as the first character after the opening bracket * - ``$`` - Match the end of the file * - ``.`` - Matches any single character except a newline character * - ``|`` - Alternation * - ``()`` - Grouping * - ``[]`` - Bracketed character class The following quantifiers are recognised as well: .. list-table:: :widths: 3 10 * - ``*`` - Match 0 or more times * - ``+`` - Match 1 or more times * - ``?`` - Match 0 or 1 times * - ``{n}`` - Match exactly n times * - ``{n,}`` - Match at least n times * - ``{,m}`` - Match at most m times * - ``{n,m}`` - Match n to m times All these quantifiers have a non-greedy variant, followed by a question mark (?): .. list-table:: :widths: 3 10 * - ``*?`` - Match 0 or more times, non-greedy * - ``+?`` - Match 1 or more times, non-greedy * - ``??`` - Match 0 or 1 times, non-greedy * - ``{n}?`` - Match exactly n times, non-greedy * - ``{n,}?`` - Match at least n times, non-greedy * - ``{,m}?`` - Match at most m times, non-greedy * - ``{n,m}?`` - Match n to m times, non-greedy The following escape sequences are recognised: .. list-table:: :widths: 3 10 * - ``\t`` - Tab (HT, TAB) * - ``\n`` - New line (LF, NL) * - ``\r`` - Return (CR) * - ``\f`` - Form feed (FF) * - ``\a`` - Alarm bell * - ``\xNN`` - Character whose ordinal number is the given hexadecimal number These are the recognised character classes: .. list-table:: :widths: 3 10 * - ``\w`` - Match a *word* character (alphanumeric plus “_”) * - ``\W`` - Match a *non-word* character * - ``\s`` - Match a whitespace character * - ``\S`` - Match a non-whitespace character * - ``\d`` - Match a decimal digit character * - ``\D`` - Match a non-digit character Starting with version 3.3.0 these zero-width assertions are also recognized: .. list-table:: :widths: 3 10 * - ``\b`` - Match a word boundary * - ``\B`` - Match except at a word boundary Private strings --------------- All strings in YARA can be marked as ``private`` which means they will never be included in the output of YARA. They are treated as normal strings everywhere else, so you can still use them as you wish in the condition, but they will never be shown with the ``-s`` flag or seen in the YARA callback if you're using the C API. .. code-block:: yara rule PrivateStringExample { strings: $text_string = "foobar" private condition: $text_string } Unreferenced strings -------------------- YARA 4.5.0 allows for unreferenced strings in the condition. If a string identifier starts with an ``_`` then it does not have to be referenced in the condition. Any other string must be referenced in the condition. This is useful if you want to search for particular strings and handle them in a custom callback but don't really need them for your condition logic. .. code-block:: yara rule PrivateStringExample { strings: $_unreferenced = "AXSERS" condition: true } String Modifier Summary ----------------------- The following string modifiers are processed in the following order, but are only applicable to the string types listed. .. list-table:: Text string modifiers :widths: 3 5 10 10 :header-rows: 1 * - Keyword - String Types - Summary - Restrictions * - ``nocase`` - Text, Regex - Ignore case - Cannot use with ``xor``, ``base64``, or ``base64wide`` * - ``wide`` - Text, Regex - Emulate UTF16 by interleaving null (0x00) characters - None * - ``ascii`` - Text, Regex - Also match ASCII characters, only required if ``wide`` is used - None * - ``xor`` - Text - XOR text string with single byte keys - Cannot use with ``nocase``, ``base64``, or ``base64wide`` * - ``base64`` - Text - Convert to 3 base64 encoded strings - Cannot use with ``nocase``, ``xor``, or ``fullword`` * - ``base64wide`` - Text - Convert to 3 base64 encoded strings, then interleaving null characters like ``wide`` - Cannot use with ``nocase``, ``xor``, or ``fullword`` * - ``fullword`` - Text, Regex - Match is not preceded or followed by an alphanumeric character - Cannot use with ``base64`` or ``base64wide`` * - ``private`` - Hex, Text, Regex - Match never included in output - None Conditions ========== Conditions are nothing more than Boolean expressions as those that can be found in all programming languages, for example in an *if* statement. They can contain the typical Boolean operators ``and``, ``or``, and ``not``, and relational operators ``>=``, ``<=``, ``<``, ``>``, ``==`` and ``!=``. Also, the arithmetic operators (``+``, ``-``, ``*``, ``\``, ``%``) and bitwise operators (``&``, ``|``, ``<<``, ``>>``, ``~``, ``^``) can be used on numerical expressions. Integers are always 64-bits long, even the results of functions like `uint8`, `uint16` and `uint32` are promoted to 64-bits. This is something you must take into account, specially while using bitwise operators (for example, ~0x01 is not 0xFE but 0xFFFFFFFFFFFFFFFE). The following table lists the precedence and associativity of all operators. The table is sorted in descending precedence order, which means that operators listed on a higher row in the list are grouped prior operators listed in rows further below it. Operators within the same row have the same precedence, if they appear together in a expression the associativity determines how they are grouped. ========== =========== ========================================= ============= Precedence Operator Description Associativity ========== =========== ========================================= ============= 1 [] Array subscripting Left-to-right . Structure member access ---------- ----------- ----------------------------------------- ------------- 2 `-` Unary minus Right-to-left `~` Bitwise not ---------- ----------- ----------------------------------------- ------------- 3 `*` Multiplication Left-to-right \\ Division % Remainder ---------- ----------- ----------------------------------------- ------------- 4 `+` Addition Left-to-right `-` Subtraction ---------- ----------- ----------------------------------------- ------------- 5 `<<` Bitwise left shift Left-to-right `>>` Bitwise right shift ---------- ----------- ----------------------------------------- ------------- 6 & Bitwise AND Left-to-right ---------- ----------- ----------------------------------------- ------------- 7 ^ Bitwise XOR Left-to-right ---------- ----------- ----------------------------------------- ------------- 8 `|` Bitwise OR Left-to-right ---------- ----------- ----------------------------------------- ------------- 9 < Less than Left-to-right <= Less than or equal to > Greater than >= Greater than or equal to ---------- ----------- ----------------------------------------- ------------- 10 == Equal to Left-to-right != Not equal to contains String contains substring icontains Like contains but case-insensitive startswith String starts with substring istartswith Like startswith but case-insensitive endswith String ends with substring iendswith Like endswith but case-insensitive iequals Case-insensitive string comparison matches String matches regular expression ---------- ----------- ----------------------------------------- ------------- 11 not Logical NOT Right-to-left defined Check if an expression is defined ---------- ----------- ----------------------------------------- ------------- 12 and Logical AND Left-to-right ---------- ----------- ----------------------------------------- ------------- 13 or Logical OR Left-to-right ========== =========== ========================================= ============= String identifiers can be also used within a condition, acting as Boolean variables whose value depends on the presence or not of the associated string in the file. .. code-block:: yara rule Example { strings: $a = "text1" $b = "text2" $c = "text3" $d = "text4" condition: ($a or $b) and ($c or $d) } Counting strings ---------------- Sometimes we need to know not only if a certain string is present or not, but how many times the string appears in the file or process memory. The number of occurrences of each string is represented by a variable whose name is the string identifier but with a # character in place of the $ character. For example: .. code-block:: yara rule CountExample { strings: $a = "dummy1" $b = "dummy2" condition: #a == 6 and #b > 10 } This rule matches any file or process containing the string $a exactly six times, and more than ten occurrences of string $b. Starting with YARA 4.2.0 it is possible to express the count of a string in an integer range, like this: .. code-block:: yara #a in (filesize-500..filesize) == 2 In this example the number of 'a' strings in the last 500 bytes of the file must equal exactly 2. .. _string-offsets: String offsets or virtual addresses ----------------------------------- In the majority of cases, when a string identifier is used in a condition, we are willing to know if the associated string is anywhere within the file or process memory, but sometimes we need to know if the string is at some specific offset on the file or at some virtual address within the process address space. In such situations the operator ``at`` is what we need. This operator is used as shown in the following example: .. code-block:: yara rule AtExample { strings: $a = "dummy1" $b = "dummy2" condition: $a at 100 and $b at 200 } The expression ``$a at 100`` in the above example is true only if string $a is found at offset 100 within the file (or at virtual address 100 if applied to a running process). The string $b should appear at offset 200. Please note that both offsets are decimal, however hexadecimal numbers can be written by adding the prefix 0x before the number as in the C language, which comes very handy when writing virtual addresses. Also note the higher precedence of the operator ``at`` over the ``and``. While the ``at`` operator allows to search for a string at some fixed offset in the file or virtual address in a process memory space, the ``in`` operator allows to search for the string within a range of offsets or addresses. .. code-block:: yara rule InExample { strings: $a = "dummy1" $b = "dummy2" condition: $a in (0..100) and $b in (100..filesize) } In the example above the string $a must be found at an offset between 0 and 100, while string $b must be at an offset between 100 and the end of the file. Again, numbers are decimal by default. You can also get the offset or virtual address of the i-th occurrence of string $a by using @a[i]. The indexes are one-based, so the first occurrence would be @a[1] the second one @a[2] and so on. If you provide an index greater than the number of occurrences of the string, the result will be a NaN (Not A Number) value. Match length ------------ For many regular expressions and hex strings containing jumps, the length of the match is variable. If you have the regular expression /fo*/ the strings "fo", "foo" and "fooo" can be matches, all of them with a different length. You can use the length of the matches as part of your condition by using the character ! in front of the string identifier, in a similar way you use the @ character for the offset. !a[1] is the length for the first match of $a, !a[2] is the length for the second match, and so on. !a is a abbreviated form of !a[1]. File size --------- String identifiers are not the only variables that can appear in a condition (in fact, rules can be defined without any string definition as will be shown below), there are other special variables that can be used as well. One of these special variables is ``filesize``, which holds, as its name indicates, the size of the file being scanned. The size is expressed in bytes. .. code-block:: yara rule FileSizeExample { condition: filesize > 200KB } The previous example also demonstrates the use of the ``KB`` postfix. This postfix, when attached to a numerical constant, automatically multiplies the value of the constant by 1024. The ``MB`` postfix can be used to multiply the value by 2^20. Both postfixes can be used only with decimal constants. The use of ``filesize`` only makes sense when the rule is applied to a file. If the rule is applied to a running process it won’t ever match because ``filesize`` doesn’t make sense in this context. Executable entry point ---------------------- Another special variable than can be used in a rule is ``entrypoint``. If the file is a Portable Executable (PE) or Executable and Linkable Format (ELF), this variable holds the raw offset of the executable’s entry point in case we are scanning a file. If we are scanning a running process, the entrypoint will hold the virtual address of the main executable’s entry point. A typical use of this variable is to look for some pattern at the entry point to detect packers or simple file infectors. .. code-block:: yara rule EntryPointExample1 { strings: $a = { E8 00 00 00 00 } condition: $a at entrypoint } rule EntryPointExample2 { strings: $a = { 9C 50 66 A1 ?? ?? ?? 00 66 A9 ?? ?? 58 0F 85 } condition: $a in (entrypoint..entrypoint + 10) } The presence of the ``entrypoint`` variable in a rule implies that only PE or ELF files can satisfy that rule. If the file is not a PE or ELF, any rule using this variable evaluates to false. .. warning:: The ``entrypoint`` variable is deprecated, you should use the equivalent ``pe.entry_point`` from the :ref:`pe-module` instead. Starting with YARA 3.0 you'll get a warning if you use ``entrypoint`` and it will be completely removed in future versions. Accessing data at a given position ---------------------------------- There are many situations in which you may want to write conditions that depend on data stored at a certain file offset or virtual memory address, depending on if we are scanning a file or a running process. In those situations you can use one of the following functions to read data from the file at the given offset:: int8() int16() int32() uint8() uint16() uint32() int8be() int16be() int32be() uint8be() uint16be() uint32be() The ``intXX`` functions read 8, 16, and 32 bits signed integers from , while functions ``uintXX`` read unsigned integers. Both 16 and 32 bit integers are considered to be little-endian. If you want to read a big-endian integer use the corresponding function ending in ``be``. The parameter can be any expression returning an unsigned integer, including the return value of one the ``uintXX`` functions itself. As an example let's see a rule to distinguish PE files: .. code-block:: yara rule IsPE { condition: // MZ signature at offset 0 and ... uint16(0) == 0x5A4D and // ... PE signature at offset stored in MZ header at 0x3C uint32(uint32(0x3C)) == 0x00004550 } .. _sets-of-strings: Sets of strings --------------- There are circumstances in which it is necessary to express that the file should contain a certain number strings from a given set. None of the strings in the set are required to be present, but at least some of them should be. In these situations the ``of`` operator can be used. .. code-block:: yara rule OfExample1 { strings: $a = "dummy1" $b = "dummy2" $c = "dummy3" condition: 2 of ($a,$b,$c) } This rule requires that at least two of the strings in the set ($a,$b,$c) must be present in the file, but it does not matter which two. Of course, when using this operator, the number before the ``of`` keyword must be less than or equal to the number of strings in the set. The elements of the set can be explicitly enumerated like in the previous example, or can be specified by using wild cards. For example: .. code-block:: yara rule OfExample2 { strings: $foo1 = "foo1" $foo2 = "foo2" $foo3 = "foo3" condition: 2 of ($foo*) // equivalent to 2 of ($foo1,$foo2,$foo3) } rule OfExample3 { strings: $foo1 = "foo1" $foo2 = "foo2" $bar1 = "bar1" $bar2 = "bar2" condition: 3 of ($foo*,$bar1,$bar2) } You can even use ``($*)`` to refer to all the strings in your rule, or write the equivalent keyword ``them`` for more legibility. .. code-block:: yara rule OfExample4 { strings: $a = "dummy1" $b = "dummy2" $c = "dummy3" condition: 1 of them // equivalent to 1 of ($*) } In all the examples above, the number of strings have been specified by a numeric constant, but any expression returning a numeric value can be used. The keywords ``any``, ``all`` and ``none`` can be used as well. .. code-block:: yara all of them // all strings in the rule any of them // any string in the rule all of ($a*) // all strings whose identifier starts by $a any of ($a,$b,$c) // any of $a, $b or $c 1 of ($*) // same that "any of them" none of ($b*) // zero of the set of strings that start with "$b" .. warning:: Due to the way YARA works internally, using "0 of them" is an ambiguous part of the language which should be avoided in favor of "none of them". To understand this, consider the meaning of "2 of them", which is true if 2 or more of the strings match. Historically, "0 of them" followed this principle and would evaluate to true if at least one of the strings matched. This ambiguity is resolved in YARA 4.3.0 by making "0 of them" evaluate to true if exactly 0 of the strings match. To improve on the situation and make the intent clear, it is encouraged to use "none" in place of 0. By not using an integer it is easier to reason about the meaning of "none of them" without the historical understanding of "at least 0" clouding the issue. Starting with YARA 4.2.0 it is possible to express a set of strings in an integer range, like this: .. code-block:: yara all of ($a*) in (filesize-500..filesize) any of ($a*, $b*) in (1000..2000) Starting with YARA 4.3.0 it is possible to express a set of strings at a specific offset, like this: .. code-block:: yara any of ($a*) at 0 Applying the same condition to many strings ------------------------------------------- There is another operator very similar to ``of`` but even more powerful, the ``for..of`` operator. The syntax is: .. code-block:: yara for expression of string_set : ( boolean_expression ) And its meaning is: from those strings in ``string_set`` at least ``expression`` of them must satisfy ``boolean_expression``. In other words: ``boolean_expression`` is evaluated for every string in ``string_set`` and there must be at least ``expression`` of them returning True. Of course, ``boolean_expression`` can be any boolean expression accepted in the condition section of a rule, except for one important detail: here you can (and should) use a dollar sign ($) as a place-holder for the string being evaluated. Take a look at the following expression: .. code-block:: yara for any of ($a,$b,$c) : ( $ at pe.entry_point ) The $ symbol in the boolean expression is not tied to any particular string, it will be $a, and then $b, and then $c in the three successive evaluations of the expression. Maybe you already realised that the ``of`` operator is a special case of ``for..of``. The following expressions are the same: .. code-block:: yara any of ($a,$b,$c) for any of ($a,$b,$c) : ( $ ) You can also employ the symbols #, @, and ! to make reference to the number of occurrences, the first offset, and the length of each string respectively. .. code-block:: yara for all of them : ( # > 3 ) for all of ($a*) : ( @ > @b ) Starting with YARA 4.3.0 you can express conditions over text strings like this: .. code-block:: yara for any s in ("71b36345516e076a0663e0bea97759e4", "1e7f7edeb06de02f2c2a9319de99e033") : ( pe.imphash() == s ) It is worth remembering here that the two hashes referenced in the rule are normal text strings, and have nothing to do with the string section of the rule. Inside the loop condition the result of the `pe.imphash()` function is compared to each of the text strings, resulting in a more concise rule. Using anonymous strings with ``of`` and ``for..of`` --------------------------------------------------- When using the ``of`` and ``for..of`` operators followed by ``them``, the identifier assigned to each string of the rule is usually superfluous. As we are not referencing any string individually we do not need to provide a unique identifier for each of them. In those situations you can declare anonymous strings with identifiers consisting only of the $ character, as in the following example: .. code-block:: yara rule AnonymousStrings { strings: $ = "dummy1" $ = "dummy2" condition: 1 of them } Iterating over string occurrences --------------------------------- As seen in :ref:`string-offsets`, the offsets or virtual addresses where a given string appears within a file or process address space can be accessed by using the syntax: @a[i], where i is an index indicating which occurrence of the string $a you are referring to. (@a[1], @a[2],...). Sometimes you will need to iterate over some of these offsets and guarantee they satisfy a given condition. In such cases you can use the ``for..in`` syntax, for example: .. code-block:: yara rule Occurrences { strings: $a = "dummy1" $b = "dummy2" condition: for all i in (1,2,3) : ( @a[i] + 10 == @b[i] ) } The previous rule says that the first occurrence of $b should be 10 bytes after the first occurrence of $a, and the same should happen with the second and third occurrences of the two strings. The same condition could be written also as: .. code-block:: yara for all i in (1..3) : ( @a[i] + 10 == @b[i] ) Notice that we’re using a range (1..3) instead of enumerating the index values (1,2,3). Of course, we’re not forced to use constants to specify range boundaries, we can use expressions as well like in the following example: .. code-block:: yara for all i in (1..#a) : ( @a[i] < 100 ) In this case we’re iterating over every occurrence of $a (remember that #a represents the number of occurrences of $a). This rule is specifying that every occurrence of $a should be within the first 100 bytes of the file. In case you want to express that only some occurrences of the string should satisfy your condition, the same logic seen in the ``for..of`` operator applies here: .. code-block:: yara for any i in (1..#a) : ( @a[i] < 100 ) for 2 i in (1..#a) : ( @a[i] < 100 ) The ``for..in`` operator is similar to ``for..of``, but the latter iterates over a set of strings, while the former iterates over ranges, enumerations, arrays and dictionaries. Iterators --------- In YARA 4.0 the ``for..in`` operator was improved and now it can be used to iterate not only over integer enumerations and ranges (e.g: 1,2,3,4 and 1..4), but also over any kind of iterable data type, like arrays and dictionaries defined by YARA modules. For example, the following expression is valid in YARA 4.0: .. code-block:: yara for any section in pe.sections : ( section.name == ".text" ) This is equivalent to: .. code-block:: yara for any i in (0..pe.number_of_sections-1) : ( pe.sections[i].name == ".text" ) The new syntax is more natural and easy to understand, and is the recommended way of expressing this type of conditions in newer versions of YARA. While iterating dictionaries you must provide two variable names that will hold the key and value for each entry in the dictionary, for example: .. code-block:: yara for any k,v in some_dict : ( k == "foo" and v == "bar" ) In general the ``for..in`` operator has the form: .. code-block:: yara for in : ( ) Where `` is either `any`, `all` or an expression that evaluates to the number of items in the iterator that must satisfy the condition, `` is a comma-separated list of variable names that holds the values for the current item (the number of variables depend on the type of ``) and `` is something that can be iterated. .. _referencing-rules: Referencing other rules ----------------------- When writing the condition for a rule you can also make reference to a previously defined rule in a manner that resembles a function invocation of traditional programming languages. In this way you can create rules that depend on others. Let's see an example: .. code-block:: yara rule Rule1 { strings: $a = "dummy1" condition: $a } rule Rule2 { strings: $a = "dummy2" condition: $a and Rule1 } As can be seen in the example, a file will satisfy Rule2 only if it contains the string "dummy2" and satisfies Rule1. Note that it is strictly necessary to define the rule being invoked before the one that will make the invocation. Another way to reference other rules was introduced in 4.2.0 and that is sets of rules, which operate similarly to sets of strings (see :ref:`sets-of-strings)`. For example: .. code-block:: yara rule Rule1 { strings: $a = "dummy1" condition: $a } rule Rule2 { strings: $a = "dummy2" condition: $a } rule MainRule { strings: $a = "dummy2" condition: any of (Rule*) } This example demonstrates how to use rule sets to describe higher order logic in a way which automatically grows with your rules. If you define another rule named ``Rule3`` before ``MainRule`` then it will automatically be included in the expansion of ``Rule*`` in the condition for MainRule. To use rule sets all of the rules included in the set **must** exist prior to the rule set being used. For example, the following will produce a compiler error because ``a2`` is defined after the rule set is used in ``x``: .. code-block:: yara rule a1 { condition: true } rule x { condition: 1 of (a*) } rule a2 { condition: true } More about rules ================ There are some aspects of YARA rules that have not been covered yet, but are still very important. These are: global rules, private rules, tags and metadata. Global rules ------------ Global rules give you the possibility of imposing restrictions in all your rules at once. For example, suppose that you want all your rules to ignore files that exceed a certain size limit. You could go rule by rule making the required modifications to their conditions, or just write a global rule like this one: .. code-block:: yara global rule SizeLimit { condition: filesize < 2MB } You can define as many global rules as you want, they will be evaluated before the rest of the rules, which in turn will be evaluated only if all global rules are satisfied. Private rules ------------- Private rules are a very simple concept. They are just rules that are not reported by YARA when they match on a given file. Rules that are not reported at all may seem sterile at first glance, but when mixed with the possibility offered by YARA of referencing one rule from another (see :ref:`referencing-rules`) they become useful. Private rules can serve as building blocks for other rules, and at the same time prevent cluttering YARA's output with irrelevant information. To declare a rule as private just add the keyword ``private`` before the rule declaration. .. code-block:: yara private rule PrivateRuleExample { ... } You can apply both ``private`` and ``global`` modifiers to a rule, resulting in a global rule that does not get reported by YARA but must be satisfied. Rule tags --------- Another useful feature of YARA is the possibility of adding tags to rules. Those tags can be used later to filter YARA's output and show only the rules that you are interested in. You can add as many tags as you want to a rule, they are declared after the rule identifier as shown below: .. code-block:: yara rule TagsExample1 : Foo Bar Baz { ... } rule TagsExample2 : Bar { ... } Tags must follow the same lexical convention of rule identifiers, therefore only alphanumeric characters and underscores are allowed, and the tag cannot start with a digit. They are also case sensitive. When using YARA you can output only those rules which are tagged with the tag or tags that you provide. Metadata -------- Besides the string definition and condition sections, rules can also have a metadata section where you can put additional information about your rule. The metadata section is defined with the keyword ``meta`` and contains identifier/value pairs like in the following example: .. code-block:: yara rule MetadataExample { meta: my_identifier_1 = "Some string data" my_identifier_2 = 24 my_identifier_3 = true strings: $my_text_string = "text here" $my_hex_string = { E2 34 A1 C8 23 FB } condition: $my_text_string or $my_hex_string } As can be seen in the example, metadata identifiers are always followed by an equals sign and the value assigned to them. The assigned values can be strings (valid UTF8 only), integers, or one of the boolean values true or false. Note that identifier/value pairs defined in the metadata section cannot be used in the condition section, their only purpose is to store additional information about the rule. .. _using-modules: Using modules ============= Modules are extensions to YARA's core functionality. Some modules like the :ref:`PE module ` and the :ref:`Cuckoo module ` are officially distributed with YARA and additional ones can be created by third-parties or even yourself as described in :ref:`writing-modules`. The first step to using a module is importing it with the ``import`` statement. These statements must be placed outside any rule definition and followed by the module name enclosed in double-quotes. Like this: .. code-block:: yara import "pe" import "cuckoo" After importing the module you can make use of its features, always using ``.`` as a prefix to any variable or function exported by the module. For example: .. code-block:: yara pe.entry_point == 0x1000 cuckoo.http_request(/someregexp/) .. _undefined-values: Undefined values ================ Modules often leave variables in an undefined state, for example when the variable doesn't make sense in the current context (think of ``pe.entry_point`` while scanning a non-PE file). YARA handles undefined values in a way that allows the rule to keep its meaningfulness. Take a look at this rule: .. code-block:: yara import "pe" rule Test { strings: $a = "some string" condition: $a and pe.entry_point == 0x1000 } If the scanned file is not a PE you wouldn't expect this rule to match the file, even if it contains the string, because **both** conditions (the presence of the string and the right value for the entry point) must be satisfied. However, if the condition is changed to: .. code-block:: yara $a or pe.entry_point == 0x1000 You would expect the rule to match in this case if the file contains the string, even if it isn't a PE file. That's exactly how YARA behaves. The logic is as follows: * If the expression in the condition is undefined, it would be translated to ``false`` and the rule won't match. * Boolean operators ``and`` and ``or`` will treat undefined operands as ``false``, Which means that: * ``undefined and true`` is ``false`` * ``undefined and false`` is ``false`` * ``undefined or true`` is ``true`` * ``undefined or false`` is ``false`` * All the remaining operators, including the ``not`` operator, return undefined if any of their operands is undefined. In the expression above, ``pe.entry_point == 0x1000`` will be undefined for non-PE files, because ``pe.entry_point`` is undefined for those files. This implies that ``$a or pe.entry_point == 0x1000`` will be ``true`` if and only if ``$a`` is ``true``. If the condition is ``pe.entry_point == 0x1000`` alone, it will evaluate to ``false`` for non-PE files, and so will do ``pe.entry_point != 0x1000`` and ``not pe.entry_point == 0x1000``, as none of these expressions make sense for non-PE files. To check if expression is defined use unary operator ``defined``. Example: .. code-block:: yara defined pe.entry_point External variables ================== External variables allow you to define rules that depend on values provided from the outside. For example, you can write the following rule: .. code-block:: yara rule ExternalVariableExample1 { condition: ext_var == 10 } In this case ``ext_var`` is an external variable whose value is assigned at run-time (see ``-d`` option of command-line tool, and ``externals`` parameter of ``compile`` and ``match`` methods in yara-python). External variables could be of types: integer, string or boolean; their type depends on the value assigned to them. An integer variable can substitute any integer constant in the condition and boolean variables can occupy the place of boolean expressions. For example: .. code-block:: yara rule ExternalVariableExample2 { condition: bool_ext_var or filesize < int_ext_var } External variables of type string can be used with the operators: ``contains``, ``startswith``, ``endswith`` and their case-insensitive counterparts: ``icontains``, ``istartswith`` and ``iendswith``. They can be used also with the ``matches`` operator, which returns true if the string matches a given regular expression. Case-insensitive string comparison can be done through special operator ``iequals`` which only works with strings. For case-sensitive comparison use regular ``==``. .. code-block:: yara rule ContainsExample { condition: string_ext_var contains "text" } rule CaseInsensitiveContainsExample { condition: string_ext_var icontains "text" } rule StartsWithExample { condition: string_ext_var startswith "prefix" } rule EndsWithExample { condition: string_ext_var endswith "suffix" } rule IequalsExample { condition: string_ext_var iequals "string" } rule MatchesExample { condition: string_ext_var matches /[a-z]+/ } You can use regular expression modifiers along with the ``matches`` operator, for example, if you want the regular expression from the previous example to be case insensitive you can use ``/[a-z]+/i``. Notice the ``i`` following the regular expression in a Perl-like manner. You can also use the ``s`` modifier for single-line mode, in this mode the dot matches all characters including line breaks. Of course both modifiers can be used simultaneously, like in the following example: .. code-block:: yara rule ExternalVariableExample5 { condition: /* case insensitive single-line mode */ string_ext_var matches /[a-z]+/is } Keep in mind that every external variable used in your rules must be defined at run-time, either by using the ``-d`` option of the command-line tool, or by providing the ``externals`` parameter to the appropriate method in ``yara-python``. Including files =============== In order to allow for more flexible organization of your rules files, YARA provides the ``include`` directive. This directive works in a similar way to the *#include* pre-processor directive in C programs, which inserts the content of the specified source file into the current file during compilation. The following example will include the content of *other.yar* into the current file: .. code-block:: yara include "other.yar" The base path when searching for a file in an ``include`` directive will be the directory where the current file resides. For this reason, the file *other.yar* in the previous example should be located in the same directory of the current file. However, you can also specify relative paths like these: .. code-block:: yara include "./includes/other.yar" include "../includes/other.yar" Or use absolute paths: .. code-block:: yara include "/home/plusvic/yara/includes/other.yar" In Windows, both forward and back slashes are accepted, but don’t forget to write the drive letter: .. code-block:: yara include "c:/yara/includes/other.yar" include "c:\\yara\\includes\\other.yar" yara-4.5.3/docs/yarapython.rst000066400000000000000000000434301501365277300163540ustar00rootroot00000000000000********************** Using YARA from Python ********************** YARA can be also used from Python through the ``yara-python`` library. Once the library is built and installed as described in :ref:`compiling-yara` you'll have access to the full potential of YARA from your Python scripts. The first step is importing the YARA library: .. code-block:: python import yara Then you will need to compile your YARA rules before applying them to your data, the rules can be compiled from a file path: .. code-block:: python rules = yara.compile(filepath='/foo/bar/myrules') The default argument is filepath, so you don't need to explicitly specify its name: .. code-block:: python rules = yara.compile('/foo/bar/myrules') You can also compile your rules from a file object: .. code-block:: python fh = open('/foo/bar/myrules') rules = yara.compile(file=fh) fh.close() Or you can compile them directly from a Python string: .. code-block:: python rules = yara.compile(source='rule dummy { condition: true }') If you want to compile a group of files or strings at the same time you can do it by using the ``filepaths`` or ``sources`` named arguments: .. code-block:: python rules = yara.compile(filepaths={ 'namespace1':'/my/path/rules1', 'namespace2':'/my/path/rules2' }) rules = yara.compile(sources={ 'namespace1':'rule dummy { condition: true }', 'namespace2':'rule dummy { condition: false }' }) Notice that both ``filepaths`` and ``sources`` must be dictionaries with keys of string type. The dictionary keys are used as a namespace identifier, allowing to differentiate between rules with the same name in different sources, as occurs in the second example with the *dummy* name. The ``compile`` method also has an optional boolean parameter named ``includes`` which allows you to control whether or not the include directive should be accepted in the source files, for example: .. code-block:: python rules = yara.compile('/foo/bar/my_rules', includes=False) If the source file contains include directives the previous line would raise an exception. If includes are used, a python callback can be set to define a custom source for the imported files (by default they are read from disk). This callback function is set through the ``include_callback`` optional parameter. It receives the following parameters: * ``requested_filename``: file requested with 'include' * ``filename``: file containing the 'include' directive if applicable, else None * ``namespace``: namespace And returns the requested rules sources as a single string. .. code-block:: python import yara import sys if sys.version_info >= (3, 0): import urllib.request as urllib else: import urllib as urllib def mycallback(requested_filename, filename, namespace): if requested_filename == 'req.yara': uf = urllib.urlopen('https://pastebin.com/raw/siZ2sMTM') sources = uf.read() if sys.version_info >= (3, 0): sources = str(sources, 'utf-8') return sources else: raise Exception(filename+": Can't fetch "+requested_filename) rules = yara.compile(source='include "req.yara" rule r{ condition: true }', include_callback=mycallback) If you are using external variables in your rules you must define those external variables either while compiling the rules, or while applying the rules to some file. To define your variables at the moment of compilation you should pass the ``externals`` parameter to the ``compile`` method. For example: .. code-block:: python rules = yara.compile('/foo/bar/my_rules’, externals= {'var1': 'some string’, 'var2': 4, 'var3': True}) The ``externals`` parameter must be a dictionary with the names of the variables as keys and an associated value of either string, integer or boolean type. The ``compile`` method also accepts the optional boolean arguments telling yara-python how to deal with warnings. The first argument of this nature is ``error_on_warning``. This arguments tells YARA to raise an exception when a warning is issued during compilation. Such warnings are typically issued when your rules contains some construct that could be slowing down the scanning. The default value for the ``error_on_warning`` argument is False. The second argument of this type is another boolean, ``strict_escape``, when enabled this causes YARA to produce a warning when rules contain mis-escaped characters. The default value for the ``strict_escape`` argument is False. In all cases ``compile`` returns an instance of the class :py:class:`yara.Rules` Rules. This class has a ``save`` method that can be used to save the compiled rules to a file: .. code-block:: python rules.save('/foo/bar/my_compiled_rules') The compiled rules can be loaded later by using the ``load`` method: .. code-block:: python rules = yara.load('/foo/bar/my_compiled_rules') Starting with YARA 3.4 both ``save`` and ``load`` accept file objects. For example, you can save your rules to a memory buffer with this code: .. code-block:: python import io buff = io.BytesIO() rules.save(file=buff) The saved rules can be loaded from the memory buffer: .. code-block:: python buff.seek(0) rule = yara.load(file=buff) The result of ``load`` is also an instance of the class :py:class:`yara.Rules`. Starting with YARA 4.3.0, ``Rules`` have a warning member which contains a list of warnings generated by the compiler. This allows you to know if the compiler generated warnings without them being hard errors using the `error_on_warning` argument. Instances of ``Rules`` also have a ``match`` method, which allows you to apply the rules to a file: .. code-block:: python matches = rules.match('/foo/bar/my_file') But you can also apply the rules to a Python string: .. code-block:: python with open('/foo/bar/my_file', 'rb') as f: matches = rules.match(data=f.read()) Or to a running process: .. code-block:: python matches = rules.match(pid=1234) As in the case of ``compile``, the ``match`` method can receive definitions for external variables in the ``externals`` argument. .. code-block:: python matches = rules.match('/foo/bar/my_file', externals= {'var1': 'some other string', 'var2': 100}) External variables defined during compile-time don’t need to be defined again in subsequent calls to the ``match`` method. However you can redefine any variable as needed, or provide additional definitions that weren’t provided during compilation. In some situations involving a very large set of rules or huge files the ``match`` method can take too much time to run. In those situations you may find useful the ``timeout`` argument: .. code-block:: python matches = rules.match('/foo/bar/my_huge_file', timeout=60) If the ``match`` function does not finish before the specified number of seconds elapsed, a ``TimeoutError`` exception is raised. You can also specify a callback function when invoking the ``match`` method. By default, the provided function will be called for every rule, no matter if matching or not. You can choose when your callback function is called by setting the ``which_callbacks`` parameter to one of ``yara.CALLBACK_MATCHES``, ``yara.CALLBACK_NON_MATCHES`` or ``yara.CALLBACK_ALL``. The default is to use ``yara.CALLBACK_ALL``. Your callback function should expect a single parameter of dictionary type, and should return ``CALLBACK_CONTINUE`` to proceed to the next rule or ``CALLBACK_ABORT`` to stop applying rules to your data. Here is an example: .. code-block:: python import yara def mycallback(data): print(data) return yara.CALLBACK_CONTINUE matches = rules.match('/foo/bar/my_file', callback=mycallback, which_callbacks=yara.CALLBACK_MATCHES) The passed dictionary will be something like this: .. code-block:: python { 'tags': ['foo', 'bar'], 'matches': True, 'namespace': 'default', 'rule': 'my_rule', 'meta': {}, 'strings': [StringMatch, StringMatch] } The *matches* field indicates if the rule matches the data or not. The *strings* field is a list of :py:class:`yara.StringMatch` objects. The ``match`` method returns a list of instances of the class :py:class:`yara.Match`. Instances of this class have the same attributes as the dictionary passed to the callback function. You can also specify a module callback function when invoking the ``match`` method. The provided function will be called for every imported module that scanned a file. Your callback function should expect a single parameter of dictionary type, and should return ``CALLBACK_CONTINUE`` to proceed to the next rule or ``CALLBACK_ABORT`` to stop applying rules to your data. Here is an example: .. code-block:: python import yara def modules_callback(data): print(data) return yara.CALLBACK_CONTINUE matches = rules.match('/foo/bar/my_file', modules_callback=modules_callback) The passed dictionary will contain the information from the module. You can also specify a warning callback function when invoking the ``match`` method. The provided function will be called for every runtime warning. Your callback function should expect two parameters. The first is an integer which contains the type of warning and the second is a string with the warning message. Your callback should return ``CALLBACK_CONTINUE`` to proceed with the scan or ``CALLBACK_ABORT`` to stop. Possible values for the type are:: CALLBACK_TOO_MANY_MATCHES Contents of the callback message depend on the type of the callback. For ``CALLBACK_TOO_MANY_MATCHES``, the message is a named tuple containing 3 items: ``namespace``, ``rule`` and ``string``. All contain string identifiers. Here is an example: .. code-block:: python import yara def warnings_callback(warning_type, message): if warning_type == yara.CALLBACK_TOO_MANY_MATCHES: print(f"namespace:'{message.namespace}' rule:'{message.rule}' string:'{message.string}'") return yara.CALLBACK_CONTINUE matches = rules.match('/foo/bar/my_file', warnings_callback=warnings_callback) If you do not use a warning callback a warning message will be sent to the normal python warning system for you and scanning will continue. With YARA 4.2.0 a new ``console`` module was introduced which allows you to send log messages within YARA. These are, by default, printed to stdout in yara-python, but you can handle them in your own callback using the ``console_callback`` parameter. Here is an example: .. code-block:: python import yara r = """ import "console" rule a { condition: console.log("Hello from Python!") } """ def console(message): print(f"Callback: {message}") rules = yara.compile(source=r) rules.match("/bin/ls", console_callback=console) rules.match("/bin/ls") The type of the ``message`` parameter is a string. You may also find that the default sizes for the stack for the matching engine in yara or the default size for the maximum number of strings per rule is too low. In the C libyara API, you can modify these using the ``YR_CONFIG_STACK_SIZE`` and ``YR_CONFIG_MAX_STRINGS_PER_RULE`` variables via the ``yr_set_configuration_uint32`` function in libyara. The command-line tool exposes these as the ``--stack-size`` (``-k``) and ``--max-strings-per-rule`` command-line arguments. In order to set these values via the Python API, you can use ``yara.set_config`` with either or both ``stack_size`` and ``max_strings_per_rule`` provided as kwargs. At the time of this writing, the default stack size was ``16384`` and the default maximum strings per rule was ``10000``. Also, ``yara.set_config`` accepts the `max_match_data` argument for controlling the maximum number of bytes that will be returned for each matching string. This is equivalent to using ``YR_CONFIG_MAX_MATCH_DATA`` with the ``yr_set_configuration_uint32`` in the C API. By the default this is set to 512. Here are a few example calls: .. code-block:: python yara.set_config(stack_size=65536) yara.set_config(max_strings_per_rule=50000, stack_size=65536) yara.set_config(max_strings_per_rule=20000) yara.set_config(max_match_data=128) Reference --------- .. py:module:: yara .. py:function:: yara.compile(...) Compile YARA sources. Either *filepath*, *source*, *file*, *filepaths* or *sources* must be provided. The remaining arguments are optional. :param str filepath: Path to the source file. :param str source: String containing the rules code. :param file-object file: Source file as a file object. :param dict filepaths: Dictionary where keys are namespaces and values are paths to source files. :param dict sources: Dictionary where keys are namespaces and values are strings containing rules code. :param dict externals: Dictionary with external variables. Keys are variable names and values are variable values. :param boolean includes: True if include directives are allowed or False otherwise. Default value: *True*. :param boolean error_on_warning: If true warnings are treated as errors, raising an exception. :return: Compiled rules object. :rtype: :py:class:`yara.Rules` :raises yara.SyntaxError: If a syntax error was found. :raises yara.Error: If an error occurred. .. py:function:: yara.load(...) .. versionchanged:: 3.4.0 Load compiled rules from a path or file object. Either *filepath* or *file* must be provided. :param str filepath: Path to a compiled rules file :param file-object file: A file object supporting the ``read`` method. :return: Compiled rules object. :rtype: :py:class:`yara.Rules` :raises: **yara.Error**: If an error occurred while loading the file. .. py:function:: yara.set_config(...) Set the configuration variables accessible through the yr_set_configuration API. Provide either *stack_size*, *max_strings_per_rule*, or *max_match_data*. These kwargs take unsigned integer values as input and will assign the provided value to the yr_set_configuration(...) variables ``YR_CONFIG_STACK_SIZE``, ``YR_CONFIG_MAX_STRINGS_PER_RULE``, and ``YR_CONFIG_MAX_MATCH_DATA`` respectively. :param int stack_size: Stack size to use for ``YR_CONFIG_STACK_SIZE`` :param int max_strings_per_rule: Maximum number of strings to allow per yara rule. Will be mapped to ``YR_CONFIG_MAX_STRINGS_PER_RULE``. :param int max_match_data: Maximum number of bytes to allow per yara match. Will be mapped to ``YR_CONFIG_MAX_MATCH_DATA``. :return: None :rtype: **NoneType** :raises: **yara.Error**: If an error occurred. .. py:class:: Rules Instances of this class are returned by :py:func:`yara.compile` and represents a set of compiled rules. .. py:method:: match(filepath, pid, data, externals=None, callback=None, fast=False, timeout=None, modules_data=None, modules_callback=None, warnings_callback=None, which_callbacks=CALLBACK_ALL, console_callback=None) Scan a file, process memory or data string. Either *filepath*, *pid* or *data* must be provided. The remaining arguments are optional. :param str filepath: Path to the file to be scanned. :param int pid: Process id to be scanned. :param str/bytes data: Data to be scanned. :param dict externals: Dictionary with external variables. Keys are variable names and values are variable values. :param function callback: Callback function invoked for each rule. :param bool fast: If true performs a fast mode scan. :param int timeout: Aborts the scanning when the number of specified seconds have elapsed. :param dict modules_data: Dictionary with additional data to modules. Keys are module names and values are *bytes* objects containing the additional data. :param function modules_callback: Callback function invoked for each module. :param function warnings_callback: Callback function invoked for warning, like ``yara.CALLBACK_TOO_MANY_MATCHES``. :param int which_callbacks: An integer that indicates in which cases the callback function must be called. Possible values are ``yara.CALLBACK_ALL``, ``yara.CALLBACK_MATCHES`` and ``yara.CALLBACK_NON_MATCHES``. :param function console_callback: Callback function invoked for each console module call. :raises yara.TimeoutError: If the timeout was reached. :raises yara.Error: If an error occurred during the scan. .. py:method:: save(...) .. versionchanged:: 3.4.0 Save compiled rules to a file. Either *filepath* or *file* must be provided. :param str filepath: Path to the file. :param file-object file: A file object supporting the ``write`` method. :raises: **yara.Error**: If an error occurred while saving the file. .. py:class:: Match .. versionadded:: 4.3.0 Objects returned by :py:meth:`yara.Rules.match`, representing a match. .. py:attribute:: rule Name of the matching rule. .. py:attribute:: namespace Namespace associated to the matching rule. .. py:attribute:: tags Array of strings containing the tags associated to the matching rule. .. py:attribute:: meta Dictionary containing metadata associated to the matching rule. .. py:attribute:: strings List of StringMatch objects. .. py:class:: StringMatch .. versionadded:: 4.3.0 Objects which represent string matches. .. py:attribute:: identifier Name of the matching string. .. py:attribute:: instances List of StringMatchInstance objects. .. py:method:: is_xor() Returns a boolean if the string is using the xor modifier. .. py:class:: StringMatchInstance .. versionadded:: 4.3.0 Objects which represent instances of matched strings. .. py:attribute:: matched_data Bytes of the matched data. .. py:attribute:: matched_length Length of the matched data. .. py:attribute:: offset Offset of the matched data. .. py:attribute:: xor_key XOR key found for the string. .. py:method:: plaintext() Returns the plaintext version of the string after xor key is applied. If the string is not an xor string then no modification is done. yara-4.5.3/extra/000077500000000000000000000000001501365277300136135ustar00rootroot00000000000000yara-4.5.3/extra/UltraEdit-wordfile.txt000066400000000000000000000013111501365277300200560ustar00rootroot00000000000000/L20"YARA rules" YARA_LANG Line Comment = // Block Comment On = /* Block Comment Off = */ Escape Char = \ String Chars = " File Extensions = YAR /Marker Characters = "//" /Delimiters = ~!@%^&*()-+=|\/{}[]<>:;"' , .? /Function String = "rule [a-zA-Z0-9_]*" /Indent Strings = "{" /Unindent Strings = "}" /Open Brace Strings = "{" "(" "[" /Close Brace Strings = "}" ")" "]" /C1"YARA Keywords" and at any all ascii condition contains endswith entrypoint for false filesize fullword global icontains iendswith is istartswith in include int8 int16 int32 meta matches nocase not or of private rule rva section startswith strings them true uint8 uint16 uint32 wide /C4"YARA Strings" " // / yara-4.5.3/extra/codemirror/000077500000000000000000000000001501365277300157605ustar00rootroot00000000000000yara-4.5.3/extra/codemirror/index.html000066400000000000000000000026661501365277300177670ustar00rootroot00000000000000 CodeMirror: YARA mode

YARA mode

MIME type: text/x-yara

yara-4.5.3/extra/codemirror/yara.js000066400000000000000000000055271501365277300172630ustar00rootroot00000000000000/* Language mode for CodeMirror (https://codemirror.net/) */ CodeMirror.defineMode("yara", function(config) { function words(str) { var obj = {}, words = str.split(" "); for (var i = 0; i < words.length; ++i) obj[words[i]] = true; return obj; } var keywords = words("all and any ascii at base64 base64wide condition contains endswith entrypoint filesize for " + "fullword global icontains iendswith import in include int16 int32 int8 istartswith matches meta " + "nocase not of or private rule startswith strings them uint16 uint32 " + "uint8 wide xor"); var atoms = {"true": true, "false": true}; var isOperatorChar = /[+\-*&%=<>!?|\/]/; function tokenBase(stream, state) { var ch = stream.next(); if (ch == "#" && state.startOfLine) { stream.skipToEnd(); return "meta"; } if (/[\[\]{}\(\),;\:\.]/.test(ch)) { return null } if (/\d/.test(ch)) { stream.eatWhile(/[\w\.]/); return "number"; } if (ch == "/") { if (stream.eat("/")) { stream.skipToEnd(); return "comment"; } if (stream.eat("*")) { state.tokenize = tokenComment; return tokenComment(stream, state); } } if (ch == '"' || ch == '/') { state.tokenize = tokenString(ch); return state.tokenize(stream, state); } if (isOperatorChar.test(ch)) { stream.eatWhile(isOperatorChar); return "operator"; } stream.eatWhile(/[\w\$_]/); var cur = stream.current(); if (keywords.propertyIsEnumerable(cur)) return "keyword"; if (atoms.propertyIsEnumerable(cur)) return "atom"; return "word"; } function tokenString(quote) { return function(stream, state) { var escaped = false, next, end = false; while ((next = stream.next()) != null) { if (next == quote && !escaped) {end = true; break;} escaped = !escaped && next == "\\"; } if (end || !escaped) state.tokenize = null; return "string"; }; } function tokenComment(stream, state) { var maybeEnd = false, ch; while (ch = stream.next()) { if (ch == "/" && maybeEnd) { state.tokenize = null; break; } maybeEnd = (ch == "*"); } return "comment"; } // Interface return { startState: function(basecolumn) { return {tokenize: null}; }, token: function(stream, state) { if (stream.eatSpace()) return null; var style = (state.tokenize || tokenBase)(stream, state); return style; }, electricChars: "{}" }; }); CodeMirror.defineMIME("text/yara", "yara"); CodeMirror.defineMIME("text/x-yara", "yara"); yara-4.5.3/extra/logo.ai000066400000000000000000001562441501365277300151020ustar00rootroot00000000000000%PDF-1.5 % 1 0 obj <>/OCGs[5 0 R 21 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream application/pdf logo 2015-12-10T09:39:10+01:00 2015-12-10T09:39:10+01:00 2015-12-10T09:33:55+01:00 Adobe Illustrator CS5 256 256 JPEG /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq 7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXm/5kfnF/gvXINL/AER9f9a1S69b6x6N OckkfHj6Un++61rlGTNwmqd32b2P+axmfFw0a5X3eY72NWf/ADkhdXt3FaWnlVp7mdxHDCl5VmZj QAAW+Q/M+TnT9mxEGUstAf0f+PPYdKn1WezSXU7SOxumALW8UxuAtexf04hUewp75kRJPN5rLGAl UDxDvqv0lJPzD86jyd5fGrmz+vVnSAQep6X2wxry4ydOPhkcuTgFuV2dovzOTgvh2vvZBp919csL a748PrESS8K1481DUrQVpXJRNgFxMkeGRHcVfJMHYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY q7FXYq7FXYq7FXYq7FXYq7FXYq7FXzh/zkh/ynFj/wBsyL/qInzC1P1fB7b2b/xeX9c/dFb/AM46 WFrcedLq5lXlLZ2bvb17M7pGW/4FiPpyOnFzX2jyEYAB/FJ7h+YHmS48teT9S1q2jWW4tUQQo9Sv OWVYlLAEEgF69czMkjGNh5Xs/TDPmjjPI/oFvmfzX+aPm7zTp6afqs8TWiSCb04olSrqCASRvtyP fMCWSUuZe50nZeHBLigDfvfU2kXEFt5Zsrm4kWKCCyikmlY0VUSIMzE+AAzPx/SPc+f5/wC8l7yk n/K3fyv/AOpp0z/pJj/rk2plqOjoroQyMAVYdCDuDiqXa95m8veX7eO51vUbfTbeV/TiluZFjVno W4gt3oCcVQWi/mB5I1y+Fho+uWV/elS4t7eZJH4r9o8VPQYqu13z15N0C7Sz1vWrPTrqSMTJBczJ G5jZiocBj0LIR9GKpd/yt38r/wDqadM/6SY/64q2v5uflezBR5p0ypNBW6iA+8nFWR6bqumanard 6beQX1q/2Li2kSaM/J0LLiqnrWu6Nodib/WL2GwslYI1xcOI0DNso5HbfFUp0v8AMnyBqt/Dp+m+ YLC8vrgkQ20M6PI5ALEKoNTsCcVQmpfm9+Wmm6mdLu/MFqt8riNoULSlXJpxYxq6hq9QTiqYa1+Y HkjQ742Gsa5ZWF6FDm3uJkjfi32TxY9DiqA/5W7+V/8A1NOmf9JMf9cVbX82/wAsGYKPNOmVY0Fb qIDfxJNBirJrHULDULZbqwuYru2f7E8DrJGfkyEg4qr4q7FXYq7FXYq7FXYq7FXYq7FXYq7FXzh/ zkh/ynFj/wBsyL/qInzC1P1fB7b2b/xeX9c/dFI/yT1v9FfmHp4ZuMOoB7GX39YVjH/I1UyvFKpB yu28HiaaXfH1fL9lvo7zzoba75Q1bSkFZbm3b0B4yp8cf/DqMzcsbiQ8Voc/hZoz7j9nV8bkEEgi hGxBzXPpb681b/yV17/2w5f+oQ5ssX0j3Pl2o/vJe8vz/wAmwfpBpn/HNtP+MMf/ABEYsXiH/OX3 /KEaN/20x/1DyYpDyz/nFn/ya8P/ADBXP6hipegf85GflN+YHnDzvY6n5d0r69ZQ6ZFbSS/WLaGk q3E7leM0kbfZkU1pTFQ8s/6Fw/Of/qXv+nyx/wCq+KbQWr/kP+bWk2E1/e+XpRawKXlaGa2uGVVF S3CGWR6Ae2K2lH5f/mF5g8ka9DqmlTt6QYfXLEsfRuIq/Ejr0rT7LdVPTFX09/zkjqFtqX5KrqNq 3O1vZrK4gbxjl+NT9xxYh8reS7TzNeeZbS08sBm1y4EsVmEdIm+OF1fi8jIqn0y1DUffiyZvp3/O O35xw6hazSeX+Mcc0bu31yxNFVgSdp8UWz78/Pyd/MbzV+YMuraBpH1zT2tYIhP9YtYvjQHkOMss bbfLFQ85/wChcPzn/wCpe/6fLH/qvim0u138jvzV0LTZdS1LQJUsoAWmlilt7goo3LMsEkjBR3NK DFbQv5Z/mTrvkXzDBf2M7nT3kUalp9f3c8NaMCp2DgfZbqD7VGKl96288VxbxXELcopkWSNvFWFQ fuOLFUxV2KuxV2KuxV2KuxV2KuxV2KuxV84f85If8pxY/wDbMi/6iJ8wtT9Xwe29m/8AF5f1z90W Vfl/+Rmj2lrp3mDW7ySa7VYr1beMiOGMiki82pzbjtXcZLHgFcRLru0O3ZyMseMVHcX1PRPvMX58 +R9KMsNq82qXcdV9OBCkYYdmkk4/eobJy1Mem7iabsHUZKJqI8/1B806ldre6jdXixiFbmaSYQqa hBIxbiDt0rTMJ7nFDhiI86FPrTVv/JXXv/bDl/6hDmyxfSPc+Y6j+8l7y/P/ACbB+kGmf8c20/4w x/8AERixeIf85ff8oRo3/bTH/UPJikPLP+cWf/Jrw/8AMFc/qGKl9C/mn+ePlj8v2js54n1LWpk9 RNOgZU4IejTSHlwDdvhJ9qYoeUv/AM5j35YlPK0QSvwg3jEge5EI/Vimlp/5zF1Eih8rwkH/AJe2 /wCqWK0+e764S5vbi4jiEEc0jyJCv2UDMSFHTZa0xS+mfzIZm/5xX8vFiWP1fTBU77BQAPoGKHkH 5A/+Tf8ALf8Axml/6h5MUl90YsXmX5p/n15Z8g3Q0xoJNV1soJGsYWEaxqwqvrSkNxLdgFJpv4VV eYN/zmNqHI8fK0IWuwN4xNPn6IxTSx/+cw790ZH8qwMjAhlN2xBB2IIMWK0+dcUv0H/LiWSb8vPK 80h5SSaRYO7bCrNbRknbFiyLFXYq7FXYq7FXYq7FXYq7FXYq7FXzh/zkh/ynFj/2zIv+oifMLU/V 8HtvZv8AxeX9c/dFmv5LfmJ5v8yyyWGo2kU1jYxAPqaAxsG6IjKKo5IB6UyeDJImujqu2uzsOACU SRKR+lP/AM3NN8mr5S1HUtbsoXuViZLO4CqtwbhlIiVJB8X2tyOlB0yeeMeGzzcTsjJn8aMcZNXv 3V1fKmYL6A+wb63lufy2uLeFeUs2jPHGo7s1qQB95zZYvpHufLtR/eS95fn3k2D748p/mb5D1by9 YXkGuWUXKCMSQT3EUUsbhBySRHYMGU/2bYsXlH/OV3mDQdT8m6RFp2pWt7Kmohnjt545WC+hIKkI zECpxSHnn/OLP/k14f8AmCuf1DFSwr809Ru9Q/MjzNc3dfW/SVzFxbcqkMpijT/YIgX6MUh6l+RX kX8lNb8sS3nm68tptaM7q1lc3rWfpRLx4FVSSFn5deW47dsUF6V/yqb/AJxl/k07/uLz/wDZVii3 yPrcNrBrN/DaU+qxXMyW/FuQ9NZCEoxJr8PeuLJ9JfmN/wCsreX/APjBpv6sUPIfyB/8m/5b/wCM 0v8A1DyYpL7oxYvz08+ahd6h51168u2LXE1/clye1JWAX5KBQYsg9l/JLyB+RuseT0vvNN5bXOuS SSfWbS5vmszAoYrGqoksJYMo5cjXr7YoJehf8qm/5xl/k07/ALi8/wD2VYot8dYsn6Cfll/5Lbyn /wBsbT/+oWPFiyXFXYq7FXYq7FXYq7FXYq7FXYq7FXzx+f8AYXWo/mRpFhaLzubuwt4YU8XkuZ1X 8TmFqPqD2Xs/kENLOR5CRP8AsQ9u8oeVtP8ALGgW2kWSjjCKzS0o0srAc5G92P3DbMrHDhFPLazV Sz5DOXX7B3PnH84vPsvmjzI9vbP/ALh9NZobNR0kYGjzHx5EfD/k/M5g5cnEfJ7XsbQDBis/XLn+ pgGVu4fa/l//AI4Om/8AMLB/ybXNlj+ke58uz/3kveXzj+b/APzjNq76tPrfkeJbm2u3MtxpBdY5 IpGNWMLSFVZD14k1Hao6TawXlh/I/wDNn/qWbz7k/wCasU2lHmT8vfOnlm1iu9e0mfT7ed/SikmC gM9C3EUJ7DFbZ5/ziz/5NeH/AJgrn9QxQXoP56/8486xrWtz+afKKLcXN4eepaYzrGxkAp6sLOQp 5U+JSeu4rXZUF4yfyP8AzZ/6lm8+5P8AmrFNu/5Uf+bP/Us3n3J/zVitu/5Uf+bP/Us3n3J/zVit voDzz5L8033/ADjtovl2002abW7eKwWaxUD1FMQ+MHenw4sXmn5M/lR+YujfmboWp6poNzaWFtLI 09xIF4oGgkUE0J7kDFJL67xQ+afzt/5xz12/1+78y+Tokukv3M17pXJYpFmbd5Ii5VGDn4iKg16V 7KQXkv8Ayo/82f8AqWbz7k/5qxTbv+VH/mz/ANSzefcn/NWK27/lR/5s/wDUs3n3J/zVitvtLyBY 3dh5E8uWF5EYLy00uyguYW+0kkduiOp91YUxYp9irsVdirsVdirsVdirsVdirsVdirxj8wL+zsPz 48rXN4QsC2kKMzdFMk1zGrH5MwOYmU1MPTdn45T7PyiPPiP3RezkAgg9Dscy3mXzl+af5RaB5R0R tWtdRmZ5rhYbWylVTs1WI5Ch+FV60zAy4uHq9r2V2vk1GTgMRsNy8myl6F9o6XM0Pla0mUAtFYxu oPSqwgiubLH9I9z5dqP7yXvL5b/6G6/Mn/q26N/yIuv+ynJtdO/6G6/Mn/q26N/yIuv+ynFaYD+Y v5r+bfP9xbSa48KQWfL6tZ2qGOFDJTk3xM7sTxH2mNO2Kaep/wDOKPkPWv8AENx5uu7aS30uK1e3 sZZFKieWVhUx1+0qKpqelT88UF9SYodirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVd irsVdirsVYt5p/LTyj5o1CPUNYtnmuoohboySyRj01ZnAopA6ucrniEjZc/S9p5sEeGBoXfJPtL0 2HTbGOygklkhhHGMzyNK4XsObksae5yUY0KcTLkM5cRqz3bJb5r8k+XvNUNvDrULzR2rM8ISR46F gAa8CK9MjPGJc2/Sa3JpyTjNWxv/AJUP+W3/ACwS/wDSRN/zVkPy8XN/l7Vfzh8gzqOyt47FbJVP 1dIhCq1NeAXjSvXplwFCnUykZEk9Xmf/AELL+UH/AFapv+ku4/5rwsbd/wBCy/lB/wBWqb/pLuP+ a8VtMNI/5x+/KTS51uIdAjuJkbkpu5Jrhdu3pyu0ZHzXFXoUcaRoscahEQBURRQADYAAYq3irsVd irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdi rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir sVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs VdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV dirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVd irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdi rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir sVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs VdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsV dirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVd irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdi rsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir sVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs VdirsVdir//Z uuid:91f869a7-49a3-b04e-bb5d-b31bdb5179ca xmp.did:FD7F1174072068119109D8284DAF73E2 uuid:5D20892493BFDB11914A8590D31508C8 proof:pdf uuid:b793da81-910d-904c-b6eb-fb165ce2789b xmp.did:F87F1174072068119109D8284DAF73E2 uuid:5D20892493BFDB11914A8590D31508C8 proof:pdf saved xmp.iid:0180117407206811822AE61051C92AC8 2015-12-08T18:34:02+01:00 Adobe Illustrator CS6 (Macintosh) / saved xmp.iid:F87F1174072068119109D8284DAF73E2 2015-12-10T09:25:38+01:00 Adobe Illustrator CS5 / saved xmp.iid:FD7F1174072068119109D8284DAF73E2 2015-12-10T09:33:53+01:00 Adobe Illustrator CS5 / Document Print False False 1 987.777778 987.777778 Millimeters Cyan Magenta Yellow Black Default Swatch Group 0 Adobe PDF library 9.90 endstream endobj 3 0 obj <> endobj 7 0 obj <>/Resources<>/Properties<>>>/Thumb 26 0 R/TrimBox[0.0 0.0 2800.0 2800.0]/Type/Page>> endobj 23 0 obj <>stream HTˊ$DTN[@+!F-gvl+=3"annߏot?o}co+Mc<|ϖV9rKV{8ӪogEm% ß5d}V:g|d,XJ=kQΜr+g[gr*Lˁ<9bi츤usjJ􄊅-kaQbdm^HVj,Pkj9+?rgxtTÉRWD֕˖"6wXJX֙r^7qVy 9$!C%Έ:U{kkѓ>KXvXI޽jm6[goТGTh6/:M{v%RzjZGAgӏV)qR%Ά"&]2U8@ kM=yJ:tgtR:;)^DIIym1#.ݹ\/V67M IBw# 5 0]*pV觢,RE׎)-dEu(׺oSOC*I",>۾-|pw;`™׊~kEhc;E-%*&Y*NBTBBY,$@ՋQ C%O#DlXJilPg8;^y DI tIv:?E%Cϖ8ާYVΤqҚVNeAJPoC43R%9ȤamnIqVݟoI8 &R9`d+e#4sxf6*!MAV q?fB)wC:ἨB$>{y1ҵQ8X*QBS#D !Yc>f{q>KOhei5[V;l? OJTxW2`Y.#KbҕXɸƯT5iZ"{pbO="z9%)o^G/8;}[$Qb}?'VVOTvEHm5I |wli ?~˛R$ƥƗRPE nRjPgzޮKAUB@R{H.N`w_ RiHA\56qiЀ[crfbFrUcz<IOUswKQ%q@{^#([;h[g,!-tr $SLG㒃o]^pI/\h6"Ȗ?4em&rbPjJqEDEFX!QYYDam!1tϼ?1m7L[r@o6*,,BDvEiSL Q\5S[[,p'^ hyU"5*Uʰ!m3 Q~K!W5%Q݂ .4-GA]|iy&\,՜ %u! A)\ͰpRmE= V0jOq!jz]ʹ0Tt+ըQj5RҘ`)Vt5,NdUu? !|YO{ʗlNݠ&j!5Xxt _+a%U m04dM^mSO?PQuԒ%zx6}~l|O\h:,eIQ-[nФ˼Yl]72 ,; Wb5@ޛ@Y`EBh' dP$z1Rx>_&rg,eRSYg|d+N &qꅸJUU" Lz`e$gWL0@v/Ft =9A{/ƨR`MWUФ U׵sìt#S΋ɻI(?~R+H 7 <jo%!ZF>kFЫ#gTY:Qa|Tf]N`9<\ ݛ6_.GdDPLΤMW4zAiP9IH);;B"1cD"F$N$xE*> eU endstream endobj 26 0 obj <>stream 8;Z\ulOC`S%"oKFs#_7lGVlU&0IAnM>_D>Dd &G'G*>EA8V73&;\F+I#I[>l6kG\EZA;AkJ5hEmkh5F7\W^8*n@d8Tj'A3-@Y%m4%mt8$SsP,MA3L=69CNU8Xkg UpCe)[t[p\MSJ3a96Nm1=%7J"'^b"EF<6_'J'oQ[Vp;2&ZJ6SWrT7]BH*hYIaZr$QLE8Ssa)a7X*Yp4TGH^z!!!#6c"d=5,Y'B~> endstream endobj 27 0 obj [/Indexed/DeviceRGB 255 28 0 R] endobj 28 0 obj <>stream 8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn 6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 21 0 obj <> endobj 29 0 obj [/View/Design] endobj 30 0 obj <>>> endobj 25 0 obj <> endobj 24 0 obj <> endobj 31 0 obj <> endobj 32 0 obj <>stream %!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 15.0 %%AI8_CreatorVersion: 15.0.2 %%For: (plusvic) () %%Title: (logo.ai) %%CreationDate: 10/12/15 09:39 %%Canvassize: 16383 %%BoundingBox: 0 0 2800 2800 %%HiResBoundingBox: 0 0 2800 2800 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 11.0 %AI12_BuildNumber: 399 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%CMYKProcessColor: 1 1 1 1 ([Registration]) %AI3_Cropmarks: 0 0 2800 2800 %AI3_TemplateBox: 1399.5 1399.5 1399.5 1399.5 %AI3_TileBox: 1094 1004 1706 1796 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 1 %AI9_ColorModel: 2 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI9_OpenToView: 642.875 1718.875 16 1620 999 26 0 0 43 135 0 0 0 1 1 0 1 1 0 1 %AI5_OpenViewLayers: 7 %%PageOrigin:1102 979 %AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 33 0 obj <>stream %%BoundingBox: 0 0 2800 2800 %%HiResBoundingBox: 0 0 2800 2800 %AI7_Thumbnail: 128 128 8 %%BeginData: 5054 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF %FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFF %FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFAFFCAFFCAFFCAFFA8FD78FFA093 %93936F9393A0CAFD04FFCA8DCAFD70FFA06893699368A0FD06FFA093A1FD %70FFA0939393699AFD07FFC98DCAFD70FFA168936993A0FD04FFC9999A6F %93A1FD70FFA09369938DC9FD04FF6F938D9369CAFD70FFA169936993A1FF %FFFFCA9368936993A1FFFFA8527D527DA8FD05FF7D5252597DFFFFA8527D %527D527D527D527D7DFD05FFA853527D52FF7D522752FF7D527D527D527D %527D527D7DFD34FFA09393938DC3FD04FFFD049369CAFFFF7D27272720FD %06FF7D20272752FFFF7D2720272727202727272027277DFFFFFFA8202727 %277DFD0427FF52272027272720272727202727A8FD32FFA16993699393FD %04FF9A68936993A1FFFF7DF827F827A8FD05FF5227F82752FFFF7DF827F8 %27F827F827F827F827F87DFFFF8427F8272027F827F852FF52F827F827F8 %27F827F827F827F8A8FD31FFA09393936993CAFFFFFFA19369938DCAFFFF %7D27F82727FD06FF7D2727F852FFFF7DFD0B27F82727FFFFA82727F8FD05 %2752FF52FD0B27F82727FD31FFA06893699368C3FD04FF6F936893A1FFFF %7EF827F827A8FD05FF5227F82752FFFFFFA8FFA8FFA8FFA8FFA87DF827F8 %277DFF7D27F827F8A8FFFFA8FFFFFFA8FFA8FFA8FFA8FFA852F827F827A8 %FD30FFA093939369939AFD04FFA069938DCAFFFF7D27202727FD06FF7D27 %27207DFD0DFF522027277DFFA827272027A8FD10FF27202727A8FD30FFA1 %6893699AA0FD05FF9A936993A1FFFFA8F827F827A8FD05FF5227F82752FD %05FFA8A8A8AFA8A8A8FF5227F82752FF7D27F827F8AFFD08FFA8A8A8AFFD %04A82727F8277DFD30FFA09369A0FD04FFCAC99993939369CAFFFF7D2727 %2720FD06FF7DF8272752FFFFFF84FD04272027272720272727F87DFFA8F8 %272727A8FD06FF7DFD04272027272720272727F87DFD30FFA16993A1FFFF %FF9A93699369936993A1FFFF7DF827F827A8FD05FF5227F82752FFFF7DF8 %27F827F827F827F827F827F82752FF7E27F827F8A8FD05FF52F827F827F8 %27F827F827F827F82753FD30FFA09393CFFD04FFA7A0FD049369CAFFFF7D %FD0427FD06FF7D20272752FFFF272720FD0B27207DFFA820272727A8FD04 %FFA8272720FD0B27207DFD30FFA169936FC3CAFD04FFA168936993A1FFFF %7DF827F827A8FD05FF5227F82752FF7D27F827F87DA8FFA8FFFFFF5227F8 %2752FFA827F827F8A8FD04FF5227F827F87DFFFFA8FFFFFF2727F8277DFD %30FFA093939369A0FD04FFA09369938DCAFFFF7D27F82727A8FD05FF7D27 %27F853FF7DF8272727A8FD06FF53F827277DFFA82727F827A8FD04FF52F8 %272727FD07FF27F827277DFD30FFA068936993A8FFFFFFA19369936893A1 %FFFFA8F827F827277D7D7E7DA82727F82752FF5227F827F8527DA87D7D7D %A82727F82752FF7D27F827F8A8FD04FF5227F827F8527D84FD047D2027F8 %277DFD30FFA0938D93A7FD04FF9A8D9393938DCAFFFFFF52202727272027 %272720272727207DFFA82027272720272727202727272027277DFFA82727 %2027A8FD04FF7E2027272720272727202727272027277DFD30FFA16893A0 %FD04FF9A689369936993A1FFFFFFA852F827F827F827F827F827F82752FF %FF59F827F827F827F827F827F827F82752FF7D27F827F8A9FD05FF52F827 %F827F827F827F827F827F8277DFD30FFA09393FD04FFCA8D936993939369 %CAFD05FF7DF8272727F8272727F8272752FFFFFF7DFD0427F8272727F827 %2727F87DFFA8F8272727A8FD06FF7DF8272727F8272727F8272727F87DFD %30FFA169A1FD04FF6F93699369936993A1FD06FFA87DA87DA87DA85227F8 %2752FD05FF7DA87DA87DA87DA87DA87DA8A8FFA8A87DA87DFD08FFA87DA8 %7DA87DA87DA87DA87DA8A8FD30FFA093CAFFFFFFCA938DFD059369CAFD0D %FF5220272752FD5EFFA169CFFD04FFA09A939369936993A1FFFFFFFD087D %5352F827F82752FD5EFFA093CAFD06FFCA939369938DCAFFFFA827F82727 %27F8272727F8272727F8A8FD5EFFA0689AFD06FF9A9369936893A1FFFFA8 %F827F827F827F827F827F8272784FD5FFFA0938DC3FD05FF9A8DFD0493CA %FFFFA82720FD0827527DFD62FFA8CAA7FD05FFA8CAA8CAA8CACFFFFFFFA8 %A8A8AFA8A8A8AFA8FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFD %FCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFD %FCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDAEFFFF %%EndData endstream endobj 34 0 obj <>stream %AI12_CompressedDataxܽz*9(zn{ ` Lhn`]ߏڏNa={? *T*j7=fHy^hZs45oj|X.= 7F2%@C6lSnY#<,·[_hwZ.7Ӎw0wpmQ da[1-X|#BG,̴(E57k!G7I A'qXRz}$O1O1`ʎ>=`.7qV]hAmK[6c8F#`2|C c,3O0(Q'ƒ840Uu0y5z>$IH= 7gz SkvrOwާ&@[Xsd}k0`1 xe 5ixFOal vf43ֆ?h,y)lU@`X4edџܿo Xe̯_r cۀj/mD[MP [@0 j"A{`?ZwffٟѯGcbH1 Z+csr>|$@9yv cY 7n%K}@%S+5hz I7lZ6y>xԅ/Ę'P,WYo^?qar}σet|9( aV-zv c|? 0ϝ*cd`_C0$@QA܁}PH8X t;jp\Dc$?*g]&}7N|10wB-c-`枆 r x0p/6}ϖ}@+j?_5ZڻC'If4M6Iχ==r%@ybuIcv7]|*; =oxw1\܌XNkYH^f=h 6` > NŢH&Ӏ|CinB]QLA!L_,5xvxD4GoY{aGnUjg"͚8{Fu<ZZrz=rc+qmPqo tc)㗤~9_S=6hf$MnOў~C`=E>7|4ӛ|IU?tF87/n]Ð!M6(?VCj|Y||϶3;3咋[)B(pVTtI,m󸮒 fCCqs4X~ciEF{f`H  `A$b+фoޞj{JrO 22a=S;I_iR͚u" k IZ.qN#fES \8 #W 绽 !ʬKh$֊,Z٢>.Hـ0zBTy_B"x!7*Y#ZMq*үf]ƼbcHG@ Uنrֺ|;Dd4)3)AUdOP4%U dP%NPf-R 3h|(jSZl)&FFbQQp n7zlA3|G3&ZL`6 F3 qbSoyV!1Zv\w]5 ـ$.HbZKbrHUH]2c`J-̶ڨ52i,nht3IH.AM8 ?Cܬ`BΖSŴb<ċ>Ӄn;@7w 9ŌX޻D*ujh8'z4 D9 9h9Bͪh| 0 'j5h>;-T Rk_$_#}+|3MuRaˡ޼e75?!n"IimexW:(~;ʕw[E{i<1X!?zde'>Y6?"퍁 v?M鱬>tFQŞdue߮tZQgh%F~ LA|qviyh!Sm;҉Y` '_zd[nv@=E!6 [FE8>`~ɧ;MeAjM;ځyy[RܦJqV0TiS~ !Rم#aY=)$o&; D]b|+T9wvW*Up;]21y; ղ! h};%t5`#*~ >"uQq'oa0dחXyrz~ҜS5 1BtNVs/1YYI#x#6WLq Gh}{ (҉ޜi=CP7ājSۨ>N?ԚHa&?;2bC4%pJ Sl93ve]Lۨ'~\a2k+S7^49@0崽X.E:{taeTfNuew7;\oȝءAO={?8>'KmrC=_feT=2"X\w?~]H̎ˆ~74O9 e!&>5uÍB6,n&yvy6g XJZ_pMts5a>C=ph,}{ C.tW낵:Yd t@Y GʟJ6lKÙ}~9L<Ȉ p_}*\~"lcɟY#eV0%g*v ]7XT-_ZX)^01<\lUII S4ix{K5c=ՖZ5~’}>7_^0\/Xœ 8"I_ q Ix3;GO/%R}9-V[Er>Q1ROkͼ<7Xon0խwY(Z]l,YL5zG}zw9b=`kl9s5@~c(Qi7cc*ӷz-Ҁ0~BQ}bInaToNQ}1ͭYUIwtLKiںin~]FoGÎ~#Kbj]Li(Ʈr'zsg{~c)jx|P=RW}Ls0ܙb[v M.2X_OFmgyI$chib^poI Cd*~V{ $Yv@<C>)s{ oͿ 0_:dA^@޷6@d g%+e5$$,7!Zfzth{L-^-ny=KӴ'v29|طNo%жnf39›KOS9-2V&k FfD۲|MQ#21"#$I[b2z$ŜQttKQ\Kp\T)c扡$K˧+)~}Ot AY0 t{:`SC{fV\\ح~fU0+D-}3͑ (ro˻Bqc}ͮj1ZCK)Aځ Z'-8{dwZ4UҴO6Wac@kNpoSMahD` 179-fRJ#fb(oй2=*\vG4D'ހUTlt2k3"sSB&䩼@AAcAPG{EKV'uaZCXLTsЭg6] |%'br&mݚtT3|؃EZg}07QuP>]rhЅF*uKqZG:@|e r%؍0\8P^4IG "\n%cD҆[,0 PpW7kLcSݵ1g)-|qFdLtmoQErbnOXd,' ^4Mx+j6 `ϣ.a`.z0ԯ o1Y'^4q2c;֩ߺs|"& M#7CJ>+D&Ͻul  !t%jF8yPEDJGb fyՇ/]EXUxrsj Tz^ 7A0.eZS\7>n&yt(;&b<K􎚭\%{VVfKz6 +h:ꋐSgoX#~T4IBiBOcTzx^XSBæB,q-܂9:BڈQ˴:b=IH8jfs/ùRWZ>MMRf(*`etc@,ļ؉6fNz+6Mn4A)N pR03EJ+/̏h^Io۪5Q6ju uZ P I2Bhrkl;]-Chm&aGq>4\yf?S[XB\.i#f6F36~ڛo_CC`Qj7OwU`4 6C o)=cb[bF ZNi ##J:޷;/4RhVB6 -2zTm[SӁpȄB!UW6`ǁ^*a(=fJdғ IgC2meP7\G=[ .勠zWNԈs8ixX4PkxZpE<Pl̋x:czꄋۊz-qC>"؎Ʈh 9VLǗP15&vN/`Iq}l7#=զh‘Ӝɖ=I} ?+XE%m!EO-gl7{5L2m?W<t8(g)jh#W-Eg31l4`ǿ)7[_3l` `c1O0ua~q`r4 5k#. zH8TMM `Kv̅X|;A[,ؙ:^bvתx;v~,WpO+_!16̀B/FR=>דu?70^oA"pgXiQ40w=?(ߙ<>[`5R3gs{5ɛ<ēu}Ȕsw\~}h ~QJ>3Xi:u7̸ϏJlo=.ПDm2w#ҙY,ӆӣh:hr{&O5F&UV01_,M}vt7,g #+2Xѐv/[oKF^.Z[=giIoynM'vms`!@'HD Fio=R%ӭ0iph)Aʍ%Z:,^lY}H݅ȎΖ>吺`Ribi?$H!6}'pMYu9Dq2*+"*e쎉RʏϵpN9,Һ͆",oijAuqJG-?3(!ѽ(ّG\pZ~Ç'*Y٢M# :Y8V^ Hk(W@M% EhK7wUj*m+csZ\E0Xw{:ZJVX]]2H}%<!Z펢HkK`xn?\D{GZ Iia "F| 6ы#z,qߙC $LwSkNJH7}Vi9`)"1YakC x:_ĭnYz" uo*!}" ^ixe8?&…uRzC|uޝ>#ĭg&JOD?܏)<`,^g%|`'c'C 6ʋQb ;OVin%w%wul*;deњeLr:~iJ?}QzJ&V ilh}re7gFzV5+|RYVZJ3$i}{[غts/$7zG\Wqך[o&0[6d?wu)s@$Z|@s8;HXf᜝ړHCiM6Hݎ2Rsq ZGK[0͟JHU<1Z.H"r3&8f;4ؼ1X*"EܦxsG~ / G+"ʯH0RH/eQ$ -X_fw7a[&tA ~VsԙvPZ GDKx~#rE#\8 +>M_I7 kS-]kR i\0A!}|b,ߟ< 6^[+1#_?dkWb0쀱. Va8F80'" NoF孀?%NM.$WDGO.;IҕG#? $3~ҚzIlHds&\'Kn (>B^n9K+9ʫ}@y-6սry&Xx7Gފ SfQ@]-JUuvv]ehWlKV%.W% 힬Tu ` N44E}hUަVƥ`URG¨nQ3{@Pś %#>T8A_},7;E`0,^wh :,D6?OT[$m9xPh)D&~gǼ'"Pu yX\=#&9 k/rV0 S=EVqb`Tb0%TERtDnle֓`]rX1v.AOtʟ}=wL:q,*R<sqjXX4l~|5LʱA:jˁBr20B&-MlQLî;ejHS)F8>+q\NOQIc6fӲXѫ wgʪr 7em0J P*8 MR:nA:}0X ԗZtEK hvuiQG c0+ і&% 7b yR`PЏ@0_@~$f씨K{^ κ9ZrH<ۻlrCHt-KAʳ /\{oIgxf~TɁSUd4b.q9b!(0|LXehK\Iӌ.nfj,adcF#@V @;$ 5r]&Y=ۭ'š87_Iu*U҉ >~ QEzEG- sm ['(ล}4 g"\ŽgY-YNW i Y^1֛ 'f_nսi45qRфh+BJΥ) ޡVyׄ7 ΋U ڀ-p`i4juޮa*g-ָnmrP! isJCbUsAOg(\8m86Tׅ24{N׆*0nRmE($@G><%a( ]E4,H7,iWbV*Z13iVsceb_G5tN%#DqK%G$zɊNZWM-k@Iǟ̤(3y5|# STHe^Nڽ4XğoO119'wQM/0>% XpLD]R K;/,fb_9@rڬlyP(nҽb+U/ ::5t. :b:<긂?%: :Z: L9|Q z^-xI zJI5ttx%5ttjk+-vy zkЩW1c9NR7-NWGtDzA69EFNȋ_޺\r=8t2iqR+SǓS0>i͈9F. z_L钮GȕJb;ԢdM. g#pn)]CH&uYvj*N(%iOQ02 g!VhIJ  BdЊ.2f퉐-1S+a<)pc~H(L8IJ,qviʚ JUk''U,/:>'R.M`F|I-#ikOD0eD((/#O)S޽8b7Q,p 0q9^R脪4gtٲeibHXT8/ZZݤt=RGN$nر5LkQf;y\Aa!+M2ˁו S 9u2y}:aCaĦujdۯth1dۯrRek<'p2s0u9qjUa[Q*f>:X44i`|GYEjԁx^]"oשHBE*i\"JE*syE*rTX} $O~ ,CSu%oxZ.+õ gA_NXl1?R w_yR)D,c2"4#/.CguNlSLȂń'q]i2+=Zn@wg0]!ڛ 谈MPS{.ntIrҷ#,hT`Ϣ=dע7{ӄW Vxx$H;x7- ou2gT!YDXetY]"NZ,̯}NeQv/Oه7R]V("Ej+ [PYr]ORF /S;KT.Q{I70Uӊv3*uՊݦ>rukT}|G"Rӧ%D^Zp+U\==Uƺ,8Wvg>Ap̂!Ǹ v% U-vr{doWDyiDbI>j|UZfŜ+;Z7b}$'AiNgn3_R )Dz?7T2^!;9iuوɝvv {F]&녘T[P ~TXCi%/t]+cgt`N] ]l)OUmk Xkm[[2rG#U^`*)d8s7'ʕK jV)p.?%sm"QI:-W,B vxu o2 gDϸN}2@]jYpU>qwb wgݔwr=My.C wwÝAj^ L5N_XKeFA[+)\u%\!8Y9We ҕ־ ]68o+0ٸo*"iRbeLjEjC{^^H[X::w_٧x_vJ.a(*N1jV 5nictMyָyv(RvTGuÝZ[Æy#:Λ:}*%v#k\՛ =e3PѴcEz.k5>²~n%cJi|=\|XGExK?9a]{W!oTDzK>GJHNJi.mbc,3J.ZNެJXWF;"R#-7'`cU)84wAe%w[GfBJZUCZ)"w)RKyZYbzG}ӮwXq 2l:5Mw%2)dDWGQVVQӑ6x2A\BVQc2r敻Lo&bot[Q<n^ΕEw$#y NSR4ҜiUiJszuӉYZ=p|9zݭ^WidN7'ʭLoscŮakhu`%- mTօt=ckk{F=M&:Xq`@bZ^KA5KKW|L4B c+aÀYD訃0auusaWX*Gs^_TeJ6`)}]dN⸤nPH=H%5VCspmqK(yj) 6D}ݥw͟Rn"JkfZ]i)֫dWf-)֙#9S)H;*Y:ߕvjxU*ʜqB5O[J~EH i7식P jUHլV- 'U*PJ'ߨ'#[#^Gu֥|gv|WO#pK I?t)=cS|_yΥ|Q)JRMd;3: gCwr%½~g uƽ~CP½~)O gC{.?JϽ~+/O\(CϺ/zd穣|i\'~LsS'~7p{2TsEX 9g*^zcg'JQ:DNtv55S;>sCpR)1Xs #.O<_JLV?i@{+ROO Muڽ~%&{ߙx}|=`]TzKueO=y!sٽ~|ɕla4^1^?m9v{o}|ZIz;0{½~y_ӼOYœqZ/W^~,{]Z+/O*/O\9^pߥ,ɭ~ǧ W%J^sٚċ-ã[+ȱSOtBSwY]IV?qK1ŤWt dnR`NV?ig~4,g~= VV?,xѽ~g0g8hGwuƽ~z-/O]9T=Pc XpvY}.ME'ދQ5O[I LN=',{k %P:gMo|̐ѷߖ2QXOUvdtݚ` dg&OƕH\DjPO(V^2@7*Qzys&SfD)#Z6M6_݁xĻA| 5L~#'diw} m>-r Mv(/ѕ}oņ&h^3&G9hlmXq7>ۑNM3,}ML`lr?u&tey>rtȄ|$W?h49ł) 5{:Mo_ًV{{}O( (;|ۯ !n?= H}aYmL H}f*p&w=y='<4=07.Bss vUp,4H(]dxqnh/?<éˋ(F$"G78;@2i#aߐ? {!7^^XX}@.Xy hyqN@,}k.Sg>TSS6HvNQ.&_`_w2VßK8|_p{dMZ- 2 UB쏊pr}ܻD1X|{s? T?!n,aF(_6wK' ]\8uSxn5H/}E_$͏{oANRnwsyWQ,Q\nCå%/NI~3"KKeþ[|| hYO6r%<^"[aP;>*PFz3wR/;YAH}ss %XොZs~S*#I@B qQ! vtw'=Ή8,ˤꂢ°.wcrCE/.`|/#B  )r*33 0Ų`YpH˔4Hfϖggvy ~(eFz"osRMcz)0߽A ,agI`b"A{p7͍~?\izr}N3La5K22{0?L3{\fg ֲ+LF'b4``j![`[4|s),\87M/2x\4NnJnMG"\ =c}2iPh ī @mj]/QZ>=sr̗JwL+Hn$ߟz:AL/vR<~0os¶{#",2ڲ h1rC5Xu c ZH(Vz; z1#{I1'Աعb3u]:\Ե"Q'?bH o&4ʈv4ffL⺺tYk/.WPlU &{ rY_Djr8~Є>]zwCCw@L2e_>rp٘ü]9\:[P;JG0vs:y__a|3뚆 01ɘ!c T]{s2õ.;r\ew~sP JXOk8^ V[zImgq6ezA@_~PWtz'nr[5]t$Ź=*B|PNDt|k|%vZ?? |-׋95HDMv[cO!rĭYerH'a. 7r{=VU\C9=`~@´oc~`XkN籗vk`kB# OY^grz:3gy W&I?5yYי IKfq qpݷeWe.%l9幘w3Mܖ/2sz& װ'Ѽe|(@u骇h(auqhA߈^!{UYъF?cQbN \}(PIfc{YۉNt%$1X-7^ *rPQ,E\.6+04sogiLKož |@,Roܹ='jLX:G]!kUܙ6=lЊLq>$\lg?Ê?;hڙUNFGщģi>?; {|Wx4l>?7h?7G38pv?R.y78+RE0{YVxT&LtviLO߆6E ͜˘6&܁p  X~{F~3S%?897VAC> өgxs;Vŀ3nτ'p ߕw)Dk{߾v}J{X,vP ;݈K` WbT{f>L}736?z|K)flךIH7wܪtt ,,Ų5\,32$< >,G'BGLF:0'1=k#UP$#}_Ma,RfJ$@w gHm uO`i++@:`4>aǨhM+H$ {I r`~.KQJU3t$,r*R&`pu: .0nX@ G"}@² :f#~YRYL&NJ H=PQyn? lA;s97@.aU0KϣczԧAPyw";kI9/\\=\ : @ϐ:wkSBRQL/%39B~ys+K-\.YwL "@(,I`FQic7t.=L],Do{BW7x O'GŊ6'9$"F77S4饧\QN福XGw:`yGӻ T5\Xc41~h^=mN3_`ie9\ @/h:z>y""ʢ|;Zk |0F$?_ISI|O\-V9[jX9,($Ve7HƧkk1YN~gJ0#W΂Ţ0їXTLۨVa|gb"\X4/-?^[R aWkC݀W[<>HloCm8pAEAS"v_MYX3h~\*mP=$7 keŒ`A!d$|0' w}G(ldL}vzڷNG*i{Okg5" 342EC3Hp9ܲMtvi0 ݋mr_XGU#ՒTw7^V>M_ʡI:$|qDQ}"!0|zsc;se@zT"3՛W B'=A`3m`~2O),{Pk>Q9ߔ!P4%Et6 /@HST>Vzo}f!S͘2C^| "ʾcXiQ4 MIsk0'-.l>)x^omC<;Eë绸1qD 0ft%KE7oqlw"^춊wM1r~`,O|z잁/KN::dw.C4StsqrpdDblX>wO^u~3r-IB2Wvs`ѡzf/j?hǎsWc+ lRi7~.^ExU?X^XE2G\JD9`KEAХL12#J5jqK~$puT/T?xxc ,zX u5$a6xZ>tPtk^i*Ez(wn'3XχJ`.˼&sHeieop'#u:p>ê 7lxw06c&P|(ci4 @ZԆZ΃14ȟ2* /I4+ʠI>~g̷磋{? ٮ M}U^'] N0SGp_@' Tؚ;IKuPJWщ6[1Xo.g MCC3nعrp"aqg2X91'[dw9+%|BQp@‘=^ESwFZʟL^&PnO{M#g145gݲ]yzR;U 9Lkx9=9Ц3{6p|hP0+50V?du؎%R7^ | @. vH7M{Q?tPn M'=OXLfC1l1Y7|D$&bD YR>L7OC7V[K浵Kޑ+Z9̱XWĪ!|]*f _vY7/gT {D-ONX$I=fH ;# D",rt: 5GmcDP $E׌m V-^}-wL sMO9V]bp\hyɊ@KՆ1x%è:`@G {^26 [}mc v! w^&aGGܚ >x%=du%>"$8^DSI_dm Jny l1s@-pGkW:vRXb >USFUzcRGcz Nsfg4(eӖ+0I m`F&;}x)  )($aϪTj}N].>pY,-ySIn"VsU'%ȪkΝ%u"(e]Rҵؠcħ]%O\p@%.$ˡ:7rV(d t+^+ ;Nv\Ł?- Fgڀ^"3; d;Nq4xD* LQţ]]W9bQ;]y_;Հ&ħ Q*w뵏seErǹdtq+&HtykV gsdça>Avq/@zu} fN$>z6la祢M$#w򛇬\ )$ ÆJ5CӮ- x,l)C`;zVKAuu HHF(_C5cum}zz@1OC72mmh!5x[}þ0f 𒡰1O"6. 1|?m$ 0: C4H7ƌ+Ƣ I2 XK܏H 0`~ _H0GH P$F+QD_7#K-ƬC {;_HDTwg[w3VVf뜈vTS@fUbVr(Kz֑lvGyl|c H/ejiQEK[ VpDkhcYGc% <:G:@Xiˉ _i{EK͔yΣ1P;JO5\gcLLe\+r9u`^Viŏk\VV܏e\ZdלaFkGJSWM6޲T0xMS:z,ǿ)S-ա׀\ KG]z옅FD6A$c ldgfO8%&ϐwG૽Wn`Ks4<1eiBwՎvFDpٲMU1b>(6k)93r0VɴpŦ#u_JPQ>Vh]I'6F:0Vzigb4< EN <$le%qF5;#z c~Vj=3=2С"ԖԈ,Ϭ=K9GR9Ϯo)e_p7 q\|)Q6p̀fH8Jt.}; [Lh*NʣN9D@VΖ[xIf-,+t&\6W`؄y6UҤ{U_!iAtҖ"*ES),/ɏ㞊\K/L~.ʀͳ:q-DZ;" QAq=8)AThG%:$- MRԭcpqCxnԈ4Rr*[ۏ MΞsmTfb.4KLXC|]vC> |,V묊P_A$ <5GTAvBB%tZMU$ aƹv4߁ ZC ry.K *DFE ys)!DՋ:?!IK?X::ϙJ]?ߋsx*%˽jB4!)g/x6:tP9:ĔHNyg28ng BΥ$yB"$Irj=pVzH5J;񖔙 moJ%=,M$+2A rFM2'@.*U%%؞{e<[rHsY-Spн7">B/Z= Pw jʡ⥕] LrHDD%!NS8 ^I>6&'4$GqD~ y0SL|^^t.5^w =I]QMTLF_ɩtx,(! #QރfoˏAZCUfi鸆b=b!RR=h@BcNsIPN%RC)Ti2 #1dҳdOLt&k"-%eO ἮLpN+CX!oӡ<ש3"aQHe&Q b7A<+ ו:A&*5 ̌ORmLn ,UBe(]Z U3 Wx̛%#[se,>AXrtu.J*>K MAA\ p6hĔ=6ڮjXܓAҊ̠Kz-15tUᝓRmQ$2UH_3I ҳuʧidZv6G rP8xk$˞,e\s޽!: d!T EuN@aJdUNeʆ\M05bLmiGFpJi)pY'DtI1$A JR𴟧C@sӝ1bJdqܛ5Jy yqT j9xp8V{@X]R @KdmZe ݳ:CrJF @dAF_q>C،c,]H0e?04/y$tBrz$[*d9'o(InC. =ӵk|k=*K}|%u5Xii>$.9hݪ>GӥZVDQu;wT%sDȿݒ$v;ջ\@<Q8Dl#-8fn6Tߌ}C#4sYVU`_Lnh0׊j;-B BѤnu;9+p?҇p޸҈[W_oU3/k% h\1+֦\ e㐥^׆,4d;|Γ\Q=VScNu6o V#W k٢D?l!q'X5yjQ$ 9ٟ2$d+ bQ bBU/QX0#j 0T^uUzEIV[ZnaVc6XkS_G89ڰn{EDܱoKU?d)'1U懕gP):M]\O HgT眚@4 UT&~#bbH^SKB).Tt{kI{DS{~__Mtg}Ø' XΜ4(?Q&JV ,:z ,NNi@_,e<" "<4nq|T~D&;9N@oT`;#Xܩ$W)rX;l裼Cv,hO(Vn>]xB%ZiC79c@&Smc.fkgq]@#JЃ Ld 6&03_cnLc&-Jl!Q>OGq"W& ͦNM'n;TjLdc2?{cKv\e4ڌaIvomt ^Yp˺ᄑ> o>W_]޽^\>ϟϯ/׏_^/ן~BXr{ݻo9I\ endstream endobj 5 0 obj <> endobj 14 0 obj [/View/Design] endobj 15 0 obj <>>> endobj 22 0 obj [21 0 R] endobj 35 0 obj <> endobj xref 0 36 0000000004 65535 f 0000000016 00000 n 0000000159 00000 n 0000016155 00000 n 0000000000 00000 f 0000055236 00000 n 0000000000 00000 f 0000016206 00000 n 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000055306 00000 n 0000055337 00000 n 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000000000 00000 f 0000020707 00000 n 0000055422 00000 n 0000016539 00000 n 0000021007 00000 n 0000020894 00000 n 0000019609 00000 n 0000020146 00000 n 0000020194 00000 n 0000020778 00000 n 0000020809 00000 n 0000021081 00000 n 0000021255 00000 n 0000022240 00000 n 0000027472 00000 n 0000055447 00000 n trailer <
]>> startxref 55615 %%EOF yara-4.5.3/extra/logo.svg000066400000000000000000000144131501365277300152770ustar00rootroot00000000000000 yara-4.5.3/extra/old-logo.png000066400000000000000000000200521501365277300160340ustar00rootroot00000000000000PNG  IHDR%E'n pHYs.#.#x?v OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FUIDATxMV`"/`e,O W`y.+T7`I@zlճD=9QHz*#E<EQE@=-%A @P%A @P%A A @P%A @P%A @P%?O5}=l/</myPz즡K;a8% ~YO Lo:)= [ B!}T@0C;E yˎ4F/8‘kA CwZ4SoY@j,F"T`O (GL=ȌW!(G?&`Gy-J%cRMEעCP0!0 -RSEQkϿ|gV6׉n_?aW뒻OS5+8S;֣[|/ŗK3z/׆wnSAaВϓ> %AcZZ>o;mvsꍄ$S ]FoކSnJڍ$j6%l}bGȹEAO$ƭ$(AN=nDPuʹ60Y$~1 i+#KI;3$(PPgZn%A ,^RZ (P_` S I#%RZ (PWf8KykJDiJ,O~ε%G Wŀ1Xڤn&)fƻ.-X%K|:Fp17o$%(g^ZtJ-Ol~ A %6=7A }߱EfN!(PĂCP`#-@PnJ (JZ (J (4}-(ɑ}i+*n*J@-c3 A"L_tnP<Գ> (AfZ Po&@PL @P ԾVntfd `wS-h~ӳ?уv&A v)8@PMBiE+`w#-@P]V A 6 uJp7FnS A yHJPadiI@Q@PMB}mokR H_1 @P9/'I%8xK;F u7 iLS-9I&48Ž7 (Ay<57ѢJwZv엱{B׮eYo7`J!uSklr9hNJ (ހƃ0$Y؂u5p+PDlŗK%kp$N0_,~?u1I@$( JA @P%A @P%A @P)(#N_C-$YcS|)_|!#tN:'nͲy$I[uzQW= ]a_ŁAэJ\2ٱVe jRm5m}hj_7nAiRߵ@<ߺzw6w=}?׺uנu|u D~(S^ϳ~uzGM D庯>^o;&>=nK~p1w^Ijgwޞ[ jJ;cnK+?-[n%Aojc\!(UZ~[5I `ۆh(pw@9ؚ0cVV^{+(UbHR{6ͪݱB}ڹ ެ`7hx3>Tz9Ȫ Ҏqz48xwm 9(U[viӑF~Q=2p^Qz[IzJ]Wt-Sn+&mU|(m9QʳÈ|aDi'nfQkaiwH츜z8q`[/;'Svێ4N6=t-|TN(=v"Jvڰ- 4Wkn8-Ɏ{T m7=zX^i[NK/nK4{6b JPje_نGN5W5,+ѱ=^]~W;[3@WU@ J[ꁒH">f/hw˟G7{nG]|f b*PVt˲t< W-"y鮑<-ݵ3HfY;@[UVUݰ 끒}Êb8?ojjm870+q$ WEyJ'@x|(m"-BT@oK-o K~_aݵqGÆdVt7[;.l`ć:]v>Hrvk@niE+GH|*.(^dMJGD#qx[ۖ?F"k1]j~gA:۱i)dUSA>u8>Pr 6,,{p^e(r?4z mny{,ڧ]ozCS vm+ ָAi $Ьz~ҦO;y֌l8 JiUվ_+(ae#4~RP[v{Zz0 bbuWe_g!wGF5h..oRnwƥ؏IKxm{<Űfz+{=m} _bqk{7vGzj5I/]sWҲ!_Y}7[zϷr#J~ob_~hĤW~?rjvh}Y5T;ժz$^qyEG๖R|͑$XƩ;wwϯ"šZpq64pدǂ&=aAddQ42(7d~P_&iGNeYyWV$rZ LZ%(cH$Աn\$(UB H)9[qweS6Y 4ЂYFĤ=Xs/9 ѿVPi)05C.UH_ww M/ղiZvBKv:NÒw*݄hR<Hhp9霤6׷+$9:~%h Adobe Photoshop CS4 (11.0x20080609 [20080609.m.379 2008/06/09:02:00:00 cutoff; m branch]) Macintosh 2008-05-13T13:58:36+02:00 2008-05-13T15:04:28+02:00 2008-05-13T14:35:59+02:00 application/vnd.adobe.photoshop xmp.iid:0A801174072068118F62D40F263793E9 xmp.did:0A801174072068118F62D40F263793E9 xmp.did:01801174072068118F62D40F263793E9 created xmp.iid:01801174072068118F62D40F263793E9 2008-05-13T14:35:59+02:00 Adobe Photoshop CS4 (11.0x20080609 [20080609.m.379 2008/06/09:02:00:00 cutoff; m branch]) Macintosh derived converted from image/tiff to application/vnd.adobe.photoshop saved xmp.iid:0A801174072068118F62D40F263793E9 2008-05-13T15:04:28+02:00 Adobe Photoshop CS4 (11.0x20080609 [20080609.m.379 2008/06/09:02:00:00 cutoff; m branch]) Macintosh /metadata xmp.iid:01801174072068118F62D40F263793E9 xmp.did:01801174072068118F62D40F263793E9 xmp.did:01801174072068118F62D40F263793E9 1 3000000/10000 3000000/10000 2 256,257,258,259,262,274,277,284,530,531,282,283,296,301,318,319,529,532,306,270,271,272,305,315,33432;939DDAB6AF1A41D058ED32CBB7E59018 600 400 32 32 32 1 2 3 1 600 400 65535 36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;4052212324FEE53A0C9873FCDB723B1D 3 sRGB IEC61966-2.1 (Linear RGB Profile) 8BIM,,8BIM&?8BIM Transparency8BIM Transparency8BIMd8BIM5d8BIM8BIM x8BIM8BIM 8BIM 8BIM' 8BIMH/fflff/ff2Z5-8BIMp8BIM8BIM 8BIM08BIM-8BIM@@'p8BIM6nullVrsnlongenabbool numBeforelongnumAfterlongSpcnlong minOpacitylong maxOpacitylong2BlnMlong8BIM3null Vrsnlong frameStepObjcnull numeratorlong denominatorlongX frameRatedoub@>timeObjcnull numeratorlong denominatorlongXdurationObjcnull numeratorlongp denominatorlongX workInTimeObjcnull numeratorlong denominatorlongX workOutTimeObjcnull numeratorlongp denominatorlongXLCntlongglobalTrackListVlLs hasMotionbool8BIM4FnullVrsnlongsheetTimelineOptionsVlLs8BIM8BIM=XlogoXnullboundsObjcRct1Top longLeftlongBtomlongRghtlongXslicesVlLsObjcslicesliceIDlonggroupIDlongoriginenum ESliceOrigin autoGeneratedTypeenum ESliceTypeImg boundsObjcRct1Top longLeftlongBtomlongRghtlongXurlTEXTnullTEXTMsgeTEXTaltTagTEXTcellTextIsHTMLboolcellTextTEXT horzAlignenumESliceHorzAligndefault vertAlignenumESliceVertAligndefault bgColorTypeenumESliceBGColorTypeNone topOutsetlong leftOutsetlong bottomOutsetlong rightOutsetlong8BIM( ?8BIMADBEmntrRGB XYZ  ;acspAPPLnone,ADBE cprt2desc$wtptrXYZgXYZbXYZrTRCgTRCbTRCtextCopyright 2008 Adobe Systems Incorporateddesc'sRGB IEC61966-2.1 (Linear RGB Profile)XYZ RXYZ o8XYZ bXYZ $curv8BIM 8BIM 'ZU'>JFIFHH Adobe_CMAdobed            U" ?   3!1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw5!1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ?TI%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$TI%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$TI%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$^mFVE7jè"Z\mv7=9 -WςVb't|K YYZ9XnAWgIxc'eZ>@>9~/_Y/}/BИX}C9~EY-i׀|j;u^~#[QlYדVEGuw10AkM/:Qo?ȞVQqwDq$R4I$$I)I$JRI$I$$I)I$JRI$I$$I)I$JRI$I$$I)I$JTI%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$tVt﫹6RNS6,z}kt /J/=޼S4匆}*IN8!Pq ]5aW*%/]73Xp2σm$BKƿ7,*Rƿ7,*SΏgz'+_EU8cW5п7Ofn~GIemp6>\Y`̷.Wyy!F#*I$ZI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IOTI%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$?BõךJ/=޼R?>A~ޓkʸ_f Wiό^嶓K>/I$q[2Mmc*u.ULkͳk:sQsq˼1-O-6Y82:OgĿ֟eIV'w>$^}iLX_nuX?u?2.m$U.[?boկRzc.öfU[_Sk^ D_Rzcweѽ߽:땻 +rzeBOlBMNNҏ^$S*I$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IOTI%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$?BõךJ/=޼R?>A~ޓkʸ_f Wiό^嶓K>/I$yoJKqSK]MޕZGzjI &(9Nj|N8lp'i$H-^?s] ߺ]ɼA+ޗ/S[WrfL<{6y//zLobKFoQ..Xʙ )7Ŀy|8I+*I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$TI%)$IJI$RI$I%)$IJI$RI$I%)$IJIVCY`^tkZs?Ǝtcg6);g  4'a\7:8]gHmL%݋ѭɾ?9Kt?>2 yV5yڿֺwZ9yڪf9PU2Jd^k)WIۿ`3TȾ}.KC]d;bJc{'s68,$Jw%I$JRI$a#*_&1}]/%g,?LՕ.Xʙ *"|KǗҋ$I$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IOTI%)$IJI$RI$I%)$IJI$RI$I%)$IO 0ks<]-~jWmؽN5UEWAT߸o>byL|=8IJIDY$I/΄xknmOvY֮ZuMI,ipb|@d_pܮnIHRI$I$/*_&ʿ)9C|WK~qyS7!eq60uv0pMƪ!/RI%yTI$$I)I$JRI$I$$I)I$JRI$I$$I)I$JRI$TI%)$IJI$RI$I%)$IJI$RI$I%)$IL\ֽp!"ABųOk,6; /c~LcVH|2|/~ p/O҈v}@f be6$=~7̏?Ǔ_[>2v&KI`=Jv zGЬo7-ۻy"3 l,ܴ'3r2=]&vg;Sױ/-*>V1{z><\ύ ¿ŗIXrI$$I)KUw_/^/kϥ/3mz{j-Fk߆eh%pGE4<AO7.WgJJ$GGɎ9!(H\f O>smtDmx$N}nggxIkN|Ħo\8ߧ17tGFlg.]Eȱc^qC̚X.N0% `~,X98/ғ$RI$I$$I)I$JRI$I$$I)I$JRI$I$TI%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$?BõךJ/=޼R?>A~ޓkʸ_f Wiό^嶓K>/I$$IJI$RNӺnFnPia.n{5mp?<7 0]pS2K$9<xcMI[>A;6O1E$k4!kDakGsdE>C5p. eBͨ}dI}I?۟yPhsEoVhkoI^'LOKFs42!o5S߷ӱ> H ψrHc$\p$Jͩ$IJI$RI$I%)$IJI$RI$I%)$IJI$STI%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$?BõךJ/=޼R?>A~ޓkʸ_f _iό^嶓K>/I$$IJI$RWG.$DHQe&5!H~.;ka;؃#v_?v]1̕(d?/E/c+W݇'f?:ޭ22qkOm5}*cϳonMhkCZ!@A:Y:WCͰkG[=HB8̖3rDp1_:.;q3?̯K%EWqG;3'^U0MoM_ˤCL+ˌ1W~~5vUSt1QB[ 3 c0rWg,?LՕ.XO4ƞ5Pr.Ŀy|(I+*I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$TI%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$Rdͷ;km >Mo[}ht [k*1w;u_Ps7;[N{%./SI*@I%)w ⾡25Yo~b7F9n#SOnN("K>. @cq{WVmJϩ$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%?TI%)$IJI$RI$I%)$IJI$RI$I%)$IJIM4qaNDIJI$RI$I%)$IJTzD}bqxd8^ӵlfy$Q1!( '+z_}XCo]:I?t}}O1Տ6ۯ&ϪtuGt%Gد_$xXx4 |:YH2o)$ $6ORI$)$IJI$;(_c*i0  JHI$$I)I$JRI$I$$I)I$JRI$I$$I)TI%)$IJI$RI$I%)$IJI$RI$I%)s^ǓF. Z q s6\M_B\~j>0[q0CTkmcw*Jt:[/7^%^v9nJ{?U4n=;*J&+2hFUOүO tbtcYk34=VgWgly'Qf52MyŰR޳oڿ= $:/\}w .񑏽՗ZC_[^m7/5UkĠ[ZcMMs*GSleJ~~-XN=[2leZƽ?5A~PY?ie8轾oyZ?Y>uetڮ.`uliWlzm/]1km-Kz5bJmNlz~N]M±^ qśO9;u _^6^7+ks[?qP}S. smmu_[+Oy%>CӾ}wzqqkhs ~_ >tT~efD9VZ_vEwW7/3a}g'e5E{W]W_XA]Ҩn[܃ˁxN1=X}pP0Zk}_M2zJu 4캗}kWYf eL9SX߮Rpo,E=v5ȢسŏP?]Һa;ӵ;c^{G}suװ_(=gY^= "J};_g|ge1ʦX6he}mWWK`}g|b0;*YAxƹǷs>4۳qWA,W;&ݏvA Z{=/Mz_Տ:+9I)]s3l?Xp 6ҳڱi~5,o~f}xk܌m~s ۉֽΫ:w?!_=mOo=?Sg:Sótme[vq7m$>u]Ya}R:}9/ί:NEW$c%R ?w_K?1cBߍqzgX3]*fC;(sEm[U}{}jS>dca]!3=^oyeMQ W޷pZWF}YmgsW6m{Y[##MٷQF8ӏ[豵6?פ}IrGXlژN-- X9rҞy}wEB -ȟsu(+adt7 y6Z%r5~Qe ԯ{2\=l3s/KK?ZJwRI$I%)$IJI$RI$I%)$IJI$RI$I%?TI%)$IJI$RI$I%)$IJI$RI$I%9Y:=[FﳲkgX^k 7_tzoڮ˗g7ǻ.|6ZcExRU\{A sS}/g_IJUcT[̐Ƌ\ѷs= $$I)^2͋?.g{}O6ڭie5p=jw阘˪=6mnjJtOJ!lZSU>iV5k;9)Ol?w:+9K0nNLȮv]UXVƽoNBN~59u5]ƇZk\\ݵ?Bwc=Lvٿk7xx;2h|o0w7uv1\7$ğ)3 Oz'|.z}kQMul֩tԶ~ELn߳ko)ħ%r/\_?_y]N>N589]^YSZZԳzwO s˩ﭶ48Z$̿_/?[TǯX=+ǩzVoٽT3zE~6]n}5KcsY^n/]b.&& ælvNihc]an;r2JkdtΝVVN-7d㙢+kYwsw`ecSn-ປ sK\6 +,rJ|٧׻C,q|;s>[z*:7LM lf08q9Z]IJI$RI$I%)$IJI$RI$I%)$IJI$RI$TI%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$TI%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$TI%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$TI%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$I%)$IJI$RI$Tʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$ꤗʩ$8BIM!UAdobe PhotoshopAdobe Photoshop CS48BIM"vMM*bj(1er2ׇi-'-'Adobe Photoshop CS4 (11.0x20080609 [20080609.m.379 2008/06/09:02:00:00 cutoff; m branch]) Macintosh2008:05:13 14:35:59Xfn(vHH8BIMmaniIRFR8BIMAnDsnullAFStlongFrInVlLsObjcnullFrIDlong2"FrDllongFStsVlLsObjcnullFsIDlongAFrmlongFsFrVlLslong2"LCntlong8BIMRoll8BIMmfri8P8BIMMt328BIMLr327g***8BIMnorm%|(YARA8BIMTySh$<??@v@sp2TxLrTxt TEXTYARA textGriddingenum textGriddingNoneOrntenumOrntHrznAntAenumAnntAnSm TextIndexlong EngineDatatdta"x << /EngineDict << /Editor << /Text (YARA ) >> /ParagraphRun << /DefaultRunData << /ParagraphSheet << /DefaultStyleSheet 0 /Properties << >> >> /Adjustments << /Axis [ 1.0 0.0 1.0 ] /XY [ 0.0 0.0 ] >> >> /RunArray [ << /ParagraphSheet << /DefaultStyleSheet 0 /Properties << /Justification 1 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /AutoLeading 1.2 /LeadingType 0 /Hanging false /Burasagari false /KinsokuOrder 0 /EveryLineComposer false >> >> /Adjustments << /Axis [ 1.0 0.0 1.0 ] /XY [ 0.0 0.0 ] >> >> ] /RunLengthArray [ 5 ] /IsJoinable 1 >> /StyleRun << /DefaultRunData << /StyleSheet << /StyleSheetData << >> >> >> /RunArray [ << /StyleSheet << /StyleSheetData << /Font 0 /FontSize 41.66667 /FauxBold false /FauxItalic false /AutoLeading true /Leading .04167 /HorizontalScale 1.2 /VerticalScale .9 /Tracking 60 /AutoKerning true /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 1 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /StrokeColor << /Type 1 /Values [ 1.0 .74902 .74902 .74902 ] >> /FillFlag true /StrokeFlag false /FillFirst false /YUnderline 1 /OutlineWidth .57884 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> >> ] /RunLengthArray [ 5 ] /IsJoinable 2 >> /GridInfo << /GridIsOn false /ShowGrid false /GridSize 18.0 /GridLeading 22.0 /GridColor << /Type 1 /Values [ 0.0 0.0 0.0 1.0 ] >> /GridLeadingFillColor << /Type 1 /Values [ 0.0 0.0 0.0 1.0 ] >> /AlignLineHeightToGridFlags false >> /AntiAlias 3 /UseFractionalGlyphWidths true /Rendered << /Version 1 /Shapes << /WritingDirection 0 /Children [ << /ShapeType 0 /Procession 0 /Lines << /WritingDirection 0 /Children [ ] >> /Cookie << /Photoshop << /ShapeType 0 /PointBase [ 0.0 0.0 ] /Base << /ShapeType 0 /TransformPoint0 [ 1.0 0.0 ] /TransformPoint1 [ 0.0 1.0 ] /TransformPoint2 [ 0.0 0.0 ] >> >> >> >> ] >> >> >> /ResourceDict << /KinsokuSet [ << /Name (PhotoshopKinsokuHard) /NoStart (00 00    0=]0 0 0 00000000A0C0E0G0I0c000000000000000000?!\)]},.:;!!  0) /NoEnd (  0;[00 0 00\([{ 0) /Keep (  %) /Hanging (00.,) >> << /Name (PhotoshopKinsokuSoft) /NoStart (00 0   0=]0 0 0 0000000) /NoEnd (  0;[00 0 00) /Keep (  %) /Hanging (00.,) >> ] /MojiKumiSet [ << /InternalName (Photoshop6MojiKumiSet1) >> << /InternalName (Photoshop6MojiKumiSet2) >> << /InternalName (Photoshop6MojiKumiSet3) >> << /InternalName (Photoshop6MojiKumiSet4) >> ] /TheNormalStyleSheet 0 /TheNormalParagraphSheet 0 /ParagraphSheetSet [ << /Name (Normal RGB) /DefaultStyleSheet 0 /Properties << /Justification 0 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /AutoLeading 1.2 /LeadingType 0 /Hanging false /Burasagari false /KinsokuOrder 0 /EveryLineComposer false >> >> ] /StyleSheetSet [ << /Name (Normal RGB) /StyleSheetData << /Font 1 /FontSize 12.0 /FauxBold false /FauxItalic false /AutoLeading true /Leading 0.0 /HorizontalScale 1.0 /VerticalScale 1.0 /Tracking 0 /AutoKerning true /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 2 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /StrokeColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /FillFlag true /StrokeFlag false /FillFirst true /YUnderline 1 /OutlineWidth 1.0 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> ] /FontSet [ << /Name (Krungthep) /Script 0 /FontType 1 /Synthetic 0 >> << /Name (MyriadPro-Regular) /Script 0 /FontType 0 /Synthetic 0 >> << /Name (AdobeInvisFont) /Script 0 /FontType 0 /Synthetic 0 >> ] /SuperscriptSize .583 /SuperscriptPosition .333 /SubscriptSize .583 /SubscriptPosition .333 /SmallCapSize .7 >> /DocumentResources << /KinsokuSet [ << /Name (PhotoshopKinsokuHard) /NoStart (00 00    0=]0 0 0 00000000A0C0E0G0I0c000000000000000000?!\)]},.:;!!  0) /NoEnd (  0;[00 0 00\([{ 0) /Keep (  %) /Hanging (00.,) >> << /Name (PhotoshopKinsokuSoft) /NoStart (00 0   0=]0 0 0 0000000) /NoEnd (  0;[00 0 00) /Keep (  %) /Hanging (00.,) >> ] /MojiKumiSet [ << /InternalName (Photoshop6MojiKumiSet1) >> << /InternalName (Photoshop6MojiKumiSet2) >> << /InternalName (Photoshop6MojiKumiSet3) >> << /InternalName (Photoshop6MojiKumiSet4) >> ] /TheNormalStyleSheet 0 /TheNormalParagraphSheet 0 /ParagraphSheetSet [ << /Name (Normal RGB) /DefaultStyleSheet 0 /Properties << /Justification 0 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /AutoLeading 1.2 /LeadingType 0 /Hanging false /Burasagari false /KinsokuOrder 0 /EveryLineComposer false >> >> ] /StyleSheetSet [ << /Name (Normal RGB) /StyleSheetData << /Font 1 /FontSize 12.0 /FauxBold false /FauxItalic false /AutoLeading true /Leading 0.0 /HorizontalScale 1.0 /VerticalScale 1.0 /Tracking 0 /AutoKerning true /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 2 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /StrokeColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /FillFlag true /StrokeFlag false /FillFirst true /YUnderline 1 /OutlineWidth 1.0 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> ] /FontSet [ << /Name (Krungthep) /Script 0 /FontType 1 /Synthetic 0 >> << /Name (MyriadPro-Regular) /Script 0 /FontType 0 /Synthetic 0 >> << /Name (AdobeInvisFont) /Script 0 /FontType 0 /Synthetic 0 >> ] /SuperscriptSize .583 /SuperscriptPosition .333 /SubscriptSize .583 /SubscriptPosition .333 /SmallCapSize .7 >> >>warp warpStyleenum warpStylewarpNone warpValuedoubwarpPerspectivedoubwarpPerspectiveOtherdoub warpRotateenumOrntHrzn8BIMluni YARA8BIMlnsrrend8BIMlyid8BIMclbl8BIMinfx8BIMknko8BIMlspf8BIMlclr8BIMshmdH8BIMcust4metadata layerTimedoubA c>dE8BIMfxrpm@Qr8!!!8BIMnorm)D(*/8BIMTySh( ??@z@s2TxLrTxt TEXT*/ textGriddingenum textGriddingNoneOrntenumOrntHrznAntAenumAnntAnSm TextIndexlong EngineDatatdta&L << /EngineDict << /Editor << /Text (*/ ) >> /ParagraphRun << /DefaultRunData << /ParagraphSheet << /DefaultStyleSheet 0 /Properties << >> >> /Adjustments << /Axis [ 1.0 0.0 1.0 ] /XY [ 0.0 0.0 ] >> >> /RunArray [ << /ParagraphSheet << /DefaultStyleSheet 0 /Properties << /Justification 1 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /AutoLeading 1.2 /LeadingType 0 /Hanging false /Burasagari false /KinsokuOrder 0 /EveryLineComposer false >> >> /Adjustments << /Axis [ 1.0 0.0 1.0 ] /XY [ 0.0 0.0 ] >> >> ] /RunLengthArray [ 3 ] /IsJoinable 1 >> /StyleRun << /DefaultRunData << /StyleSheet << /StyleSheetData << >> >> >> /RunArray [ << /StyleSheet << /StyleSheetData << /Font 0 /FontSize 41.66667 /FauxBold false /FauxItalic false /AutoLeading true /Leading 50.0 /HorizontalScale 1.2 /VerticalScale .9 /Tracking -150 /AutoKerning false /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 1 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /StrokeColor << /Type 1 /Values [ 1.0 .74902 .74902 .74902 ] >> /FillFlag true /StrokeFlag false /FillFirst false /YUnderline 1 /OutlineWidth .57884 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> >> << /StyleSheet << /StyleSheetData << /Font 0 /FontSize 41.66667 /FauxBold false /FauxItalic false /AutoLeading true /Leading 50.0 /HorizontalScale 1.2 /VerticalScale .9 /Tracking -150 /AutoKerning true /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 1 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /StrokeColor << /Type 1 /Values [ 1.0 .74902 .74902 .74902 ] >> /FillFlag true /StrokeFlag false /FillFirst false /YUnderline 1 /OutlineWidth .57884 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> >> ] /RunLengthArray [ 1 2 ] /IsJoinable 2 >> /GridInfo << /GridIsOn false /ShowGrid false /GridSize 18.0 /GridLeading 22.0 /GridColor << /Type 1 /Values [ 0.0 0.0 0.0 1.0 ] >> /GridLeadingFillColor << /Type 1 /Values [ 0.0 0.0 0.0 1.0 ] >> /AlignLineHeightToGridFlags false >> /AntiAlias 3 /UseFractionalGlyphWidths true /Rendered << /Version 1 /Shapes << /WritingDirection 0 /Children [ << /ShapeType 0 /Procession 0 /Lines << /WritingDirection 0 /Children [ ] >> /Cookie << /Photoshop << /ShapeType 0 /PointBase [ 0.0 0.0 ] /Base << /ShapeType 0 /TransformPoint0 [ 1.0 0.0 ] /TransformPoint1 [ 0.0 1.0 ] /TransformPoint2 [ 0.0 0.0 ] >> >> >> >> ] >> >> >> /ResourceDict << /KinsokuSet [ << /Name (PhotoshopKinsokuHard) /NoStart (00 00    0=]0 0 0 00000000A0C0E0G0I0c000000000000000000?!\)]},.:;!!  0) /NoEnd (  0;[00 0 00\([{ 0) /Keep (  %) /Hanging (00.,) >> << /Name (PhotoshopKinsokuSoft) /NoStart (00 0   0=]0 0 0 0000000) /NoEnd (  0;[00 0 00) /Keep (  %) /Hanging (00.,) >> ] /MojiKumiSet [ << /InternalName (Photoshop6MojiKumiSet1) >> << /InternalName (Photoshop6MojiKumiSet2) >> << /InternalName (Photoshop6MojiKumiSet3) >> << /InternalName (Photoshop6MojiKumiSet4) >> ] /TheNormalStyleSheet 0 /TheNormalParagraphSheet 0 /ParagraphSheetSet [ << /Name (Normal RGB) /DefaultStyleSheet 0 /Properties << /Justification 0 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /AutoLeading 1.2 /LeadingType 0 /Hanging false /Burasagari false /KinsokuOrder 0 /EveryLineComposer false >> >> ] /StyleSheetSet [ << /Name (Normal RGB) /StyleSheetData << /Font 1 /FontSize 12.0 /FauxBold false /FauxItalic false /AutoLeading true /Leading 0.0 /HorizontalScale 1.0 /VerticalScale 1.0 /Tracking 0 /AutoKerning true /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 2 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /StrokeColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /FillFlag true /StrokeFlag false /FillFirst true /YUnderline 1 /OutlineWidth 1.0 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> ] /FontSet [ << /Name (Krungthep) /Script 0 /FontType 1 /Synthetic 0 >> << /Name (MyriadPro-Regular) /Script 0 /FontType 0 /Synthetic 0 >> << /Name (AdobeInvisFont) /Script 0 /FontType 0 /Synthetic 0 >> ] /SuperscriptSize .583 /SuperscriptPosition .333 /SubscriptSize .583 /SubscriptPosition .333 /SmallCapSize .7 >> /DocumentResources << /KinsokuSet [ << /Name (PhotoshopKinsokuHard) /NoStart (00 00    0=]0 0 0 00000000A0C0E0G0I0c000000000000000000?!\)]},.:;!!  0) /NoEnd (  0;[00 0 00\([{ 0) /Keep (  %) /Hanging (00.,) >> << /Name (PhotoshopKinsokuSoft) /NoStart (00 0   0=]0 0 0 0000000) /NoEnd (  0;[00 0 00) /Keep (  %) /Hanging (00.,) >> ] /MojiKumiSet [ << /InternalName (Photoshop6MojiKumiSet1) >> << /InternalName (Photoshop6MojiKumiSet2) >> << /InternalName (Photoshop6MojiKumiSet3) >> << /InternalName (Photoshop6MojiKumiSet4) >> ] /TheNormalStyleSheet 0 /TheNormalParagraphSheet 0 /ParagraphSheetSet [ << /Name (Normal RGB) /DefaultStyleSheet 0 /Properties << /Justification 0 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /AutoLeading 1.2 /LeadingType 0 /Hanging false /Burasagari false /KinsokuOrder 0 /EveryLineComposer false >> >> ] /StyleSheetSet [ << /Name (Normal RGB) /StyleSheetData << /Font 1 /FontSize 12.0 /FauxBold false /FauxItalic false /AutoLeading true /Leading 0.0 /HorizontalScale 1.0 /VerticalScale 1.0 /Tracking 0 /AutoKerning true /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 2 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /StrokeColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /FillFlag true /StrokeFlag false /FillFirst true /YUnderline 1 /OutlineWidth 1.0 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> ] /FontSet [ << /Name (Krungthep) /Script 0 /FontType 1 /Synthetic 0 >> << /Name (MyriadPro-Regular) /Script 0 /FontType 0 /Synthetic 0 >> << /Name (AdobeInvisFont) /Script 0 /FontType 0 /Synthetic 0 >> ] /SuperscriptSize .583 /SuperscriptPosition .333 /SubscriptSize .583 /SubscriptPosition .333 /SmallCapSize .7 >> >>warp warpStyleenum warpStylewarpNone warpValuedoubwarpPerspectivedoubwarpPerspectiveOtherdoub warpRotateenumOrntHrzn8BIMluni*/8BIMlnsrrend8BIMlyid 8BIMclbl8BIMinfx8BIMknko8BIMlspf8BIMlclr8BIMshmdH8BIMcust4metadata layerTimedoubA cׅD8BIMfxrp@$8!!!8BIMnorm)D(/*8BIMTySh( ??@j@s2TxLrTxt TEXT/* textGriddingenum textGriddingNoneOrntenumOrntHrznAntAenumAnntAnSm TextIndexlong EngineDatatdta&L << /EngineDict << /Editor << /Text (/* ) >> /ParagraphRun << /DefaultRunData << /ParagraphSheet << /DefaultStyleSheet 0 /Properties << >> >> /Adjustments << /Axis [ 1.0 0.0 1.0 ] /XY [ 0.0 0.0 ] >> >> /RunArray [ << /ParagraphSheet << /DefaultStyleSheet 0 /Properties << /Justification 1 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /AutoLeading 1.2 /LeadingType 0 /Hanging false /Burasagari false /KinsokuOrder 0 /EveryLineComposer false >> >> /Adjustments << /Axis [ 1.0 0.0 1.0 ] /XY [ 0.0 0.0 ] >> >> ] /RunLengthArray [ 3 ] /IsJoinable 1 >> /StyleRun << /DefaultRunData << /StyleSheet << /StyleSheetData << >> >> >> /RunArray [ << /StyleSheet << /StyleSheetData << /Font 0 /FontSize 41.66667 /FauxBold false /FauxItalic false /AutoLeading true /Leading 50.0 /HorizontalScale 1.0 /VerticalScale .9 /Tracking -150 /AutoKerning false /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 1 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /StrokeColor << /Type 1 /Values [ 1.0 .74902 .74902 .74902 ] >> /FillFlag true /StrokeFlag false /FillFirst false /YUnderline 1 /OutlineWidth .57884 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> >> << /StyleSheet << /StyleSheetData << /Font 0 /FontSize 41.66667 /FauxBold false /FauxItalic false /AutoLeading true /Leading 50.0 /HorizontalScale 1.0 /VerticalScale .9 /Tracking -150 /AutoKerning true /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 1 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /StrokeColor << /Type 1 /Values [ 1.0 .74902 .74902 .74902 ] >> /FillFlag true /StrokeFlag false /FillFirst false /YUnderline 1 /OutlineWidth .57884 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> >> ] /RunLengthArray [ 1 2 ] /IsJoinable 2 >> /GridInfo << /GridIsOn false /ShowGrid false /GridSize 18.0 /GridLeading 22.0 /GridColor << /Type 1 /Values [ 0.0 0.0 0.0 1.0 ] >> /GridLeadingFillColor << /Type 1 /Values [ 0.0 0.0 0.0 1.0 ] >> /AlignLineHeightToGridFlags false >> /AntiAlias 3 /UseFractionalGlyphWidths true /Rendered << /Version 1 /Shapes << /WritingDirection 0 /Children [ << /ShapeType 0 /Procession 0 /Lines << /WritingDirection 0 /Children [ ] >> /Cookie << /Photoshop << /ShapeType 0 /PointBase [ 0.0 0.0 ] /Base << /ShapeType 0 /TransformPoint0 [ 1.0 0.0 ] /TransformPoint1 [ 0.0 1.0 ] /TransformPoint2 [ 0.0 0.0 ] >> >> >> >> ] >> >> >> /ResourceDict << /KinsokuSet [ << /Name (PhotoshopKinsokuHard) /NoStart (00 00    0=]0 0 0 00000000A0C0E0G0I0c000000000000000000?!\)]},.:;!!  0) /NoEnd (  0;[00 0 00\([{ 0) /Keep (  %) /Hanging (00.,) >> << /Name (PhotoshopKinsokuSoft) /NoStart (00 0   0=]0 0 0 0000000) /NoEnd (  0;[00 0 00) /Keep (  %) /Hanging (00.,) >> ] /MojiKumiSet [ << /InternalName (Photoshop6MojiKumiSet1) >> << /InternalName (Photoshop6MojiKumiSet2) >> << /InternalName (Photoshop6MojiKumiSet3) >> << /InternalName (Photoshop6MojiKumiSet4) >> ] /TheNormalStyleSheet 0 /TheNormalParagraphSheet 0 /ParagraphSheetSet [ << /Name (Normal RGB) /DefaultStyleSheet 0 /Properties << /Justification 0 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /AutoLeading 1.2 /LeadingType 0 /Hanging false /Burasagari false /KinsokuOrder 0 /EveryLineComposer false >> >> ] /StyleSheetSet [ << /Name (Normal RGB) /StyleSheetData << /Font 1 /FontSize 12.0 /FauxBold false /FauxItalic false /AutoLeading true /Leading 0.0 /HorizontalScale 1.0 /VerticalScale 1.0 /Tracking 0 /AutoKerning true /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 2 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /StrokeColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /FillFlag true /StrokeFlag false /FillFirst true /YUnderline 1 /OutlineWidth 1.0 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> ] /FontSet [ << /Name (Krungthep) /Script 0 /FontType 1 /Synthetic 0 >> << /Name (MyriadPro-Regular) /Script 0 /FontType 0 /Synthetic 0 >> << /Name (AdobeInvisFont) /Script 0 /FontType 0 /Synthetic 0 >> ] /SuperscriptSize .583 /SuperscriptPosition .333 /SubscriptSize .583 /SubscriptPosition .333 /SmallCapSize .7 >> /DocumentResources << /KinsokuSet [ << /Name (PhotoshopKinsokuHard) /NoStart (00 00    0=]0 0 0 00000000A0C0E0G0I0c000000000000000000?!\)]},.:;!!  0) /NoEnd (  0;[00 0 00\([{ 0) /Keep (  %) /Hanging (00.,) >> << /Name (PhotoshopKinsokuSoft) /NoStart (00 0   0=]0 0 0 0000000) /NoEnd (  0;[00 0 00) /Keep (  %) /Hanging (00.,) >> ] /MojiKumiSet [ << /InternalName (Photoshop6MojiKumiSet1) >> << /InternalName (Photoshop6MojiKumiSet2) >> << /InternalName (Photoshop6MojiKumiSet3) >> << /InternalName (Photoshop6MojiKumiSet4) >> ] /TheNormalStyleSheet 0 /TheNormalParagraphSheet 0 /ParagraphSheetSet [ << /Name (Normal RGB) /DefaultStyleSheet 0 /Properties << /Justification 0 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /AutoLeading 1.2 /LeadingType 0 /Hanging false /Burasagari false /KinsokuOrder 0 /EveryLineComposer false >> >> ] /StyleSheetSet [ << /Name (Normal RGB) /StyleSheetData << /Font 1 /FontSize 12.0 /FauxBold false /FauxItalic false /AutoLeading true /Leading 0.0 /HorizontalScale 1.0 /VerticalScale 1.0 /Tracking 0 /AutoKerning true /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 2 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /StrokeColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /FillFlag true /StrokeFlag false /FillFirst true /YUnderline 1 /OutlineWidth 1.0 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> ] /FontSet [ << /Name (Krungthep) /Script 0 /FontType 1 /Synthetic 0 >> << /Name (MyriadPro-Regular) /Script 0 /FontType 0 /Synthetic 0 >> << /Name (AdobeInvisFont) /Script 0 /FontType 0 /Synthetic 0 >> ] /SuperscriptSize .583 /SuperscriptPosition .333 /SubscriptSize .583 /SubscriptPosition .333 /SmallCapSize .7 >> >>warp warpStyleenum warpStylewarpNone warpValuedoubwarpPerspectivedoubwarpPerspectiveOtherdoub warpRotateenumOrntHrzn8BIMluni/*8BIMlnsrrend8BIMlyid 8BIMclbl8BIMinfx8BIMknko8BIMlspf8BIMlclr8BIMshmdH8BIMcust4metadata layerTimedoubA c6=l8BIMfxrp@^@"-$2338BIMnorm)({8BIMTySh(??@s@m 2TxLrTxt TEXT{ textGriddingenum textGriddingNoneOrntenumOrntHrznAntAenumAnntAnSm TextIndexlong EngineDatatdta& << /EngineDict << /Editor << /Text ({ ) >> /ParagraphRun << /DefaultRunData << /ParagraphSheet << /DefaultStyleSheet 0 /Properties << >> >> /Adjustments << /Axis [ 1.0 0.0 1.0 ] /XY [ 0.0 0.0 ] >> >> /RunArray [ << /ParagraphSheet << /DefaultStyleSheet 0 /Properties << /Justification 1 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /AutoLeading 1.2 /LeadingType 0 /Hanging false /Burasagari false /KinsokuOrder 0 /EveryLineComposer false >> >> /Adjustments << /Axis [ 1.0 0.0 1.0 ] /XY [ 0.0 0.0 ] >> >> ] /RunLengthArray [ 2 ] /IsJoinable 1 >> /StyleRun << /DefaultRunData << /StyleSheet << /StyleSheetData << >> >> >> /RunArray [ << /StyleSheet << /StyleSheetData << /Font 0 /FontSize 200.0 /FauxBold true /FauxItalic false /AutoLeading true /Leading 150.0 /HorizontalScale 1.0 /VerticalScale 1.2 /Tracking 0 /AutoKerning false /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 1 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 .54902 .00862 .00867 ] >> /StrokeColor << /Type 1 /Values [ 1.0 .74902 .74902 .74902 ] >> /FillFlag true /StrokeFlag false /FillFirst false /YUnderline 1 /OutlineWidth .57884 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> >> << /StyleSheet << /StyleSheetData << /Font 0 /FontSize 200.0 /FauxBold true /FauxItalic false /AutoLeading true /Leading 150.0 /HorizontalScale 1.0 /VerticalScale 1.2 /Tracking 0 /AutoKerning true /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 1 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 .54902 .00862 .00867 ] >> /StrokeColor << /Type 1 /Values [ 1.0 .74902 .74902 .74902 ] >> /FillFlag true /StrokeFlag false /FillFirst false /YUnderline 1 /OutlineWidth .57884 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> >> ] /RunLengthArray [ 1 1 ] /IsJoinable 2 >> /GridInfo << /GridIsOn false /ShowGrid false /GridSize 18.0 /GridLeading 22.0 /GridColor << /Type 1 /Values [ 0.0 0.0 0.0 1.0 ] >> /GridLeadingFillColor << /Type 1 /Values [ 0.0 0.0 0.0 1.0 ] >> /AlignLineHeightToGridFlags false >> /AntiAlias 3 /UseFractionalGlyphWidths true /Rendered << /Version 1 /Shapes << /WritingDirection 0 /Children [ << /ShapeType 0 /Procession 0 /Lines << /WritingDirection 0 /Children [ ] >> /Cookie << /Photoshop << /ShapeType 0 /PointBase [ 0.0 0.0 ] /Base << /ShapeType 0 /TransformPoint0 [ 1.0 0.0 ] /TransformPoint1 [ 0.0 1.0 ] /TransformPoint2 [ 0.0 0.0 ] >> >> >> >> ] >> >> >> /ResourceDict << /KinsokuSet [ << /Name (PhotoshopKinsokuHard) /NoStart (00 00    0=]0 0 0 00000000A0C0E0G0I0c000000000000000000?!\)]},.:;!!  0) /NoEnd (  0;[00 0 00\([{ 0) /Keep (  %) /Hanging (00.,) >> << /Name (PhotoshopKinsokuSoft) /NoStart (00 0   0=]0 0 0 0000000) /NoEnd (  0;[00 0 00) /Keep (  %) /Hanging (00.,) >> ] /MojiKumiSet [ << /InternalName (Photoshop6MojiKumiSet1) >> << /InternalName (Photoshop6MojiKumiSet2) >> << /InternalName (Photoshop6MojiKumiSet3) >> << /InternalName (Photoshop6MojiKumiSet4) >> ] /TheNormalStyleSheet 0 /TheNormalParagraphSheet 0 /ParagraphSheetSet [ << /Name (Normal RGB) /DefaultStyleSheet 0 /Properties << /Justification 0 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /AutoLeading 1.2 /LeadingType 0 /Hanging false /Burasagari false /KinsokuOrder 0 /EveryLineComposer false >> >> ] /StyleSheetSet [ << /Name (Normal RGB) /StyleSheetData << /Font 2 /FontSize 12.0 /FauxBold false /FauxItalic false /AutoLeading true /Leading 0.0 /HorizontalScale 1.0 /VerticalScale 1.0 /Tracking 0 /AutoKerning true /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 2 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /StrokeColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /FillFlag true /StrokeFlag false /FillFirst true /YUnderline 1 /OutlineWidth 1.0 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> ] /FontSet [ << /Name (OCRAStd) /Script 0 /FontType 0 /Synthetic 2 >> << /Name (OCRAStd) /Script 0 /FontType 0 /Synthetic 0 >> << /Name (MyriadPro-Regular) /Script 0 /FontType 0 /Synthetic 0 >> << /Name (AdobeInvisFont) /Script 0 /FontType 0 /Synthetic 0 >> ] /SuperscriptSize .583 /SuperscriptPosition .333 /SubscriptSize .583 /SubscriptPosition .333 /SmallCapSize .7 >> /DocumentResources << /KinsokuSet [ << /Name (PhotoshopKinsokuHard) /NoStart (00 00    0=]0 0 0 00000000A0C0E0G0I0c000000000000000000?!\)]},.:;!!  0) /NoEnd (  0;[00 0 00\([{ 0) /Keep (  %) /Hanging (00.,) >> << /Name (PhotoshopKinsokuSoft) /NoStart (00 0   0=]0 0 0 0000000) /NoEnd (  0;[00 0 00) /Keep (  %) /Hanging (00.,) >> ] /MojiKumiSet [ << /InternalName (Photoshop6MojiKumiSet1) >> << /InternalName (Photoshop6MojiKumiSet2) >> << /InternalName (Photoshop6MojiKumiSet3) >> << /InternalName (Photoshop6MojiKumiSet4) >> ] /TheNormalStyleSheet 0 /TheNormalParagraphSheet 0 /ParagraphSheetSet [ << /Name (Normal RGB) /DefaultStyleSheet 0 /Properties << /Justification 0 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /AutoLeading 1.2 /LeadingType 0 /Hanging false /Burasagari false /KinsokuOrder 0 /EveryLineComposer false >> >> ] /StyleSheetSet [ << /Name (Normal RGB) /StyleSheetData << /Font 2 /FontSize 12.0 /FauxBold false /FauxItalic false /AutoLeading true /Leading 0.0 /HorizontalScale 1.0 /VerticalScale 1.0 /Tracking 0 /AutoKerning true /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 2 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /StrokeColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /FillFlag true /StrokeFlag false /FillFirst true /YUnderline 1 /OutlineWidth 1.0 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> ] /FontSet [ << /Name (OCRAStd) /Script 0 /FontType 0 /Synthetic 2 >> << /Name (OCRAStd) /Script 0 /FontType 0 /Synthetic 0 >> << /Name (MyriadPro-Regular) /Script 0 /FontType 0 /Synthetic 0 >> << /Name (AdobeInvisFont) /Script 0 /FontType 0 /Synthetic 0 >> ] /SuperscriptSize .583 /SuperscriptPosition .333 /SubscriptSize .583 /SubscriptPosition .333 /SmallCapSize .7 >> >>warp warpStyleenum warpStylewarpNone warpValuedoubwarpPerspectivedoubwarpPerspectiveOtherdoub warpRotateenumOrntHrzn8BIMluni{8BIMlnsrrend8BIMlyid8BIMclbl8BIMinfx8BIMknko8BIMlspf8BIMlclr8BIMshmdH8BIMcust4metadata layerTimedoubA c0b8BIMfxrp@o@@IM# ++8BIMnorm)(}8BIMTySh(??@z0@p2TxLrTxt TEXT} textGriddingenum textGriddingNoneOrntenumOrntHrznAntAenumAnntAnSm TextIndexlong EngineDatatdta& << /EngineDict << /Editor << /Text (} ) >> /ParagraphRun << /DefaultRunData << /ParagraphSheet << /DefaultStyleSheet 0 /Properties << >> >> /Adjustments << /Axis [ 1.0 0.0 1.0 ] /XY [ 0.0 0.0 ] >> >> /RunArray [ << /ParagraphSheet << /DefaultStyleSheet 0 /Properties << /Justification 1 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /AutoLeading 1.2 /LeadingType 0 /Hanging false /Burasagari false /KinsokuOrder 0 /EveryLineComposer false >> >> /Adjustments << /Axis [ 1.0 0.0 1.0 ] /XY [ 0.0 0.0 ] >> >> ] /RunLengthArray [ 2 ] /IsJoinable 1 >> /StyleRun << /DefaultRunData << /StyleSheet << /StyleSheetData << >> >> >> /RunArray [ << /StyleSheet << /StyleSheetData << /Font 0 /FontSize 200.0 /FauxBold true /FauxItalic false /AutoLeading true /Leading 240.00002 /HorizontalScale 1.0 /VerticalScale 1.2 /Tracking 0 /AutoKerning false /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 1 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 .54902 .00862 .00867 ] >> /StrokeColor << /Type 1 /Values [ 1.0 .74902 .74902 .74902 ] >> /FillFlag true /StrokeFlag false /FillFirst false /YUnderline 1 /OutlineWidth .57884 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> >> << /StyleSheet << /StyleSheetData << /Font 0 /FontSize 200.0 /FauxBold true /FauxItalic false /AutoLeading true /Leading 240.00002 /HorizontalScale 1.0 /VerticalScale 1.2 /Tracking 0 /AutoKerning true /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 1 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 .54902 .00862 .00867 ] >> /StrokeColor << /Type 1 /Values [ 1.0 .74902 .74902 .74902 ] >> /FillFlag true /StrokeFlag false /FillFirst false /YUnderline 1 /OutlineWidth .57884 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> >> ] /RunLengthArray [ 1 1 ] /IsJoinable 2 >> /GridInfo << /GridIsOn false /ShowGrid false /GridSize 18.0 /GridLeading 22.0 /GridColor << /Type 1 /Values [ 0.0 0.0 0.0 1.0 ] >> /GridLeadingFillColor << /Type 1 /Values [ 0.0 0.0 0.0 1.0 ] >> /AlignLineHeightToGridFlags false >> /AntiAlias 3 /UseFractionalGlyphWidths true /Rendered << /Version 1 /Shapes << /WritingDirection 0 /Children [ << /ShapeType 0 /Procession 0 /Lines << /WritingDirection 0 /Children [ ] >> /Cookie << /Photoshop << /ShapeType 0 /PointBase [ 0.0 0.0 ] /Base << /ShapeType 0 /TransformPoint0 [ 1.0 0.0 ] /TransformPoint1 [ 0.0 1.0 ] /TransformPoint2 [ 0.0 0.0 ] >> >> >> >> ] >> >> >> /ResourceDict << /KinsokuSet [ << /Name (PhotoshopKinsokuHard) /NoStart (00 00    0=]0 0 0 00000000A0C0E0G0I0c000000000000000000?!\)]},.:;!!  0) /NoEnd (  0;[00 0 00\([{ 0) /Keep (  %) /Hanging (00.,) >> << /Name (PhotoshopKinsokuSoft) /NoStart (00 0   0=]0 0 0 0000000) /NoEnd (  0;[00 0 00) /Keep (  %) /Hanging (00.,) >> ] /MojiKumiSet [ << /InternalName (Photoshop6MojiKumiSet1) >> << /InternalName (Photoshop6MojiKumiSet2) >> << /InternalName (Photoshop6MojiKumiSet3) >> << /InternalName (Photoshop6MojiKumiSet4) >> ] /TheNormalStyleSheet 0 /TheNormalParagraphSheet 0 /ParagraphSheetSet [ << /Name (Normal RGB) /DefaultStyleSheet 0 /Properties << /Justification 0 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /AutoLeading 1.2 /LeadingType 0 /Hanging false /Burasagari false /KinsokuOrder 0 /EveryLineComposer false >> >> ] /StyleSheetSet [ << /Name (Normal RGB) /StyleSheetData << /Font 2 /FontSize 12.0 /FauxBold false /FauxItalic false /AutoLeading true /Leading 0.0 /HorizontalScale 1.0 /VerticalScale 1.0 /Tracking 0 /AutoKerning true /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 2 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /StrokeColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /FillFlag true /StrokeFlag false /FillFirst true /YUnderline 1 /OutlineWidth 1.0 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> ] /FontSet [ << /Name (OCRAStd) /Script 0 /FontType 0 /Synthetic 2 >> << /Name (OCRAStd) /Script 0 /FontType 0 /Synthetic 0 >> << /Name (MyriadPro-Regular) /Script 0 /FontType 0 /Synthetic 0 >> << /Name (AdobeInvisFont) /Script 0 /FontType 0 /Synthetic 0 >> ] /SuperscriptSize .583 /SuperscriptPosition .333 /SubscriptSize .583 /SubscriptPosition .333 /SmallCapSize .7 >> /DocumentResources << /KinsokuSet [ << /Name (PhotoshopKinsokuHard) /NoStart (00 00    0=]0 0 0 00000000A0C0E0G0I0c000000000000000000?!\)]},.:;!!  0) /NoEnd (  0;[00 0 00\([{ 0) /Keep (  %) /Hanging (00.,) >> << /Name (PhotoshopKinsokuSoft) /NoStart (00 0   0=]0 0 0 0000000) /NoEnd (  0;[00 0 00) /Keep (  %) /Hanging (00.,) >> ] /MojiKumiSet [ << /InternalName (Photoshop6MojiKumiSet1) >> << /InternalName (Photoshop6MojiKumiSet2) >> << /InternalName (Photoshop6MojiKumiSet3) >> << /InternalName (Photoshop6MojiKumiSet4) >> ] /TheNormalStyleSheet 0 /TheNormalParagraphSheet 0 /ParagraphSheetSet [ << /Name (Normal RGB) /DefaultStyleSheet 0 /Properties << /Justification 0 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /AutoLeading 1.2 /LeadingType 0 /Hanging false /Burasagari false /KinsokuOrder 0 /EveryLineComposer false >> >> ] /StyleSheetSet [ << /Name (Normal RGB) /StyleSheetData << /Font 2 /FontSize 12.0 /FauxBold false /FauxItalic false /AutoLeading true /Leading 0.0 /HorizontalScale 1.0 /VerticalScale 1.0 /Tracking 0 /AutoKerning true /Kerning 0 /BaselineShift 0.0 /FontCaps 0 /FontBaseline 0 /Underline false /Strikethrough false /Ligatures true /DLigatures false /BaselineDirection 2 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /NoBreak false /FillColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /StrokeColor << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> /FillFlag true /StrokeFlag false /FillFirst true /YUnderline 1 /OutlineWidth 1.0 /CharacterDirection 0 /HindiNumbers false /Kashida 1 /DiacriticPos 2 >> >> ] /FontSet [ << /Name (OCRAStd) /Script 0 /FontType 0 /Synthetic 2 >> << /Name (OCRAStd) /Script 0 /FontType 0 /Synthetic 0 >> << /Name (MyriadPro-Regular) /Script 0 /FontType 0 /Synthetic 0 >> << /Name (AdobeInvisFont) /Script 0 /FontType 0 /Synthetic 0 >> ] /SuperscriptSize .583 /SuperscriptPosition .333 /SubscriptSize .583 /SubscriptPosition .333 /SmallCapSize .7 >> >>warp warpStyleenum warpStylewarpNone warpValuedoubwarpPerspectivedoubwarpPerspectiveOtherdoub warpRotateenumOrntHrzn8BIMluni}8BIMlnsrrend8BIMlyid8BIMclbl8BIMinfx8BIMknko8BIMlspf8BIMlclr8BIMshmdH8BIMcust4metadata layerTimedoubA cԾnv8BIMfxrpS@OH́0 V@ h (!%PJ@ hRB*쀣q{[rЇl ;qp" F& a#Zn<2+\o؝x ̶^,mCFc\@XWq[Q A=: ]Ce<.T7A6D!9sRm. 2|Rvin), .ıcȸ_ UGhYrdaQZ;SpaDAtb}ю_! e?/.}Ue \rr5H2bN#B"1zNCS`3]\PQGa G܇r!RA'2C Uxap!,\&36{9΅%¹r.{?;FagַF䉏40/a>)1.hYhs15f_ep~r/+Z<<\di< ʔ0,҅0 GMuݭBthO®#"9 悽D QcU%FO މ9\ '΋|#a.p. m`XI>=/$,"V7h9=!4vϽӼ{g?ʻe'j#js1z'*sB1`^΅iR95ʹp.,9΅%¹\8 ’s\Xr. K΅saɹp.b`5H1 Om_>`<H1 Om_>`<H1 Om_>`<H̗q0ET@ *P%PBJ(\7(hбaqތo-\l "|WMkYwqL47I1+찵V`a+Tպ ةٱXJ+ B_^1ݷq8;HƃNϨu3uՈ$!^kmw0ҪդA ':&XetU}è'nhe[&Lmk;کH%j%`kTLeDErO0Gzc1F}6LltQU95FtrT꘭Eew>3ItZiA5jŦ߱%̂Se&Ϡ/SȄ.GЗuJʳ?sN Wi`\%du*;l<ZB;mEA)kغqcgefn)N-KU: :iH1 Om ?xH1 Om ?xH1 Om ?xHėQ0EUH@!P +a$J@BH,;IG&iچ|: oDwqޠ.3=wy3'CNjXW64z2 VW8wP(X`eK|W/at)SCzB& hQ:ge \! хeoRfq$WHM'@zīF;~#$E2fDSr: }f/^Pr;..^kdͨ]bЉAtb:؃NA'{Љ=tb:؃NA'{Љ=tb:؃NA'{Љ=tb:؃NA'{Љ=tb:؃NA'{Љ='/x,~A(WJ -]Sg@?-:I^{PZtϫqЌ&$4JQt( '6R4N#]çW{(7@)*']q "E&x!mC*B-~Ӈ:/C*ڎ(yJSu%Oo\?tvng4.<PEi^mZ/_͈H10TYz&0p2 HOP=A5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 j 'HOP3f =A@z5 jNWvF)!!Ji^g.wP'@7`y_xW,܉fz iD(͠s4W"7J3 gb$"%6O೰S eC*88 ^#x qK'퀇^+,3rCa8N)W > %> X`eك7MTGxJ tb:؃NA'{Љ=tb:؃NA'{Љ=tb:؃NA'{Љ=tb:؃NA'{Љ=tb:؃NA'{Љ=tb: |^ sҐr8Io=~& )ͧipvrJ"O9<& )m'\($mt2Ń: N:1؃NA'{Љ=tb:؃NA'{Љ=tb:؃NA'{Љ=tb:؃NA'{Љ=tb:؃NA'{Љ=tb:s2ߛ͟EQ yj 2;i3˚wjwS\Ɖ)q26xख़&Ks'C g,\+1+IW6SY'DXČ/xHDiN">lL!}r%IxSW6]Vf $Mp'5nMO~`u:(IK3ЋNJTD5#1-@Q@KĹQgԫjUzKwV{ Noo$DA4R5Ƀyj^\&4,,4v{WU?OH :F@Oe\' @7daryɟƎcKkկZ}#?Z|'Yz"'Yz" 9b@r*HUɑ0#Sa$GHH$($A$ & Pp$%2( EL(JdBQ2@d& %$a(! C IJHPb؄&E'&%7(O2lQ6L(&}M^=ǤcF1i옴Q4Yixshgyx&Jdm6AlM6P&(} `\*$WA&h \V! 4Mާ J&(MP4Ai J&(MP4Ai J&(MP4Ai J&(MP4Ai J&(MP4Ai J&(MP4Ai J&(MP4Ai J&(MP1)PfM Ye֤@R 0E)LfQ YdE?5ULFU*QdT6DMQjAC(Ո jDe5"se>(ue>(ue>(ue>(@d&P%3* BIMJjPRQ`C~&E؄&%6A9(oQP$EA&) 2IQɭQILBf;vwO4ILBLbbAc v&܎KBIjHRD d&L$4a"  Mȹ 3eg&tLW$c g$c g$c g$S lj Im2HR &$$Ii2IRL&$(Ie2JRT&$4A=d0%)LfI }OM4Ai J&(MP4Ai J&(MP4Ai J&(MP4Ai J&(MP4Ai J&(MP4Ai J&(MP4Ai J&(MP4Ai䏊={~3)*fRU$a&3 EI(BLbbX"eA7 lM6H&;$mId#& ʣ u+c.MXcuG=ƤMc&1i옴I4y>ɆIdäOa'x MInHr@($FA$ # MIhHBF@d&$3$ %P(IBI"Lp($@ HIBMl``*+"*+j J j J[HQVQ-,{sgoYX`}H7b7ϖ. @xHzk߇?qLp\uLf$*$HUr< &'D(q$H82Wʄ8(qL$hq(qMJM~48&&t0=ar&v,8>cr&&8bv;&_s//Vv܎u ,3(OO792 (īL3*Ϊ -晼-h-jYVT, *h4j e5AͲfYMPA&YVT, *h4j e5AͲfYMPA&YVT, *h4j e5AͲfYMPA&YVT, *h4j e5AͲfYMPA&YVT, *h4j e5AͲfYMPA&YVT, *h4j e5AͲ-& ,UeQfYPA&Y&7D U Ϣ&Sx2n(Q/&PG&'_?(>"u렔3wXy(qhMr3)@ q(qMPt&neEagQHx?(5ƣ$Lp7WMK3Ɏ~LPqM~dIIƑ=䲻$d5ag8"҄)&G,5W&ѯZ Ǿ~& $Kۑ,jWL>IRw܏dlaQj ehrC^cY֯.T, *h4j e5AͲfYMPA&YVT, *h4j e5AͲfYMPA&YVT, *h4j e5AͲfYMPA&YVT, *h4j e5AͲfYMPA&YVT, *h4j e5AͲfYMPA&YVT, *h4j e5AͲ,d♿H&q(EgZ&09A2$;nO69C2$;ϐl1Es>&5a"ejrxQ$?&v,3&OO& ;n2 &Ij.gL#&P2D3H@i #q&I =R&D$Q(D`2Dcr&&8bv;&_s//Vv܎u ,3(OO792 (īL3*Ϊ -晼-h-jYVT, *h4j e5AͲfYMPA&YVT, *h4j e5AͲfYMPA&YVT, *h4j e5AͲfYMPA&YVT, *h4j e5AͲfYMPA&YVT, *h4j e5AͲfYMPA&YVT, *h4j e5AͲ-& ,UeQfYPA&Y&7D U Ϣ&Sx2n(Q/&PG&'_?(>"u렔3wXy(qhMr3)@ q(qMPt&neEagQHx?(5ƣ$Lp7WMK3Ɏ~LPqM~dIIƑ=䲻$d5ag8"҄)&G,5W&ѯZ Ǿ~& $Kۑ,jWL>IRw܏dlaQj ehrC^cY֯.T, *h4j e5AͲfYMPA&YVT, *h4j e5AͲfYMPA&YVT, *h4j e5AͲfYMPA&YVT, *h4j e5AͲfYMPA&YVT, *h4j e5AͲfYMPA&YVT, *h4j e5AͲ,d♿H&q(EgZ&09A2$;nO69C2$;ϐl1Es>&5a"ejrxQ$?&v,3&OO& ;n2 &Ij.gL#&P2D3H@i #q&I =R&D$Q(D`2D> >> >> << /Resource << /StreamTag /CoolTypeFont /Identifier << /Name (OCRAStd) /Type 0 /Synthetic 2 >> >> >> << /Resource << /StreamTag /CoolTypeFont /Identifier << /Name (OCRAStd) /Type 0 >> >> >> << /Resource << /StreamTag /CoolTypeFont /Identifier << /Name (MyriadPro-Regular) /Type 0 >> >> >> << /Resource << /StreamTag /CoolTypeFont /Identifier << /Name (AdobeInvisFont) /Type 0 >> >> >> ] >> /MojiKumiCodeToClassSet << /Resources [ << /Resource << /Name () /Members << /ClassMappings [ << /R (55) /C 1 >> << /R (77) /C 1 >> << /R (99) /C 1 >> << /R (;;) /C 1 >> << /R (==) /C 1 >> << /R (??) /C 1 >> << /R (AA) /C 1 >> << /R (CC) /C 1 >> << /R () /C 1 >> << /R (;;) /C 1 >> << /R ([[) /C 1 >> << /R (  ) /C 1 >> << /R (00) /C 1 >> << /R (0 0 ) /C 1 >> << /R (0 0 ) /C 1 >> << /R (00) /C 1 >> << /R (00) /C 1 >> << /R (00) /C 1 >> << /R (66) /C 2 >> << /R (88) /C 2 >> << /R (::) /C 2 >> << /R (<<) /C 2 >> << /R (>>) /C 2 >> << /R (@@) /C 2 >> << /R (BB) /C 2 >> << /R (DD) /C 2 >> << /R ( ) /C 2 >> << /R (==) /C 2 >> << /R (]]) /C 2 >> << /R (  ) /C 2 >> << /R (0 0 ) /C 2 >> << /R (0 0 ) /C 2 >> << /R (0 0 ) /C 2 >> << /R (00) /C 2 >> << /R (00) /C 2 >> << /R (00) /C 2 >> << /R () /C 3 >> << /R (^^) /C 3 >> << /R (0A0A) /C 3 >> << /R (0C0C) /C 3 >> << /R (0E0E) /C 3 >> << /R (0G0G) /C 3 >> << /R (0I0I) /C 3 >> << /R (0c0c) /C 3 >> << /R (00) /C 3 >> << /R (00) /C 3 >> << /R (00) /C 3 >> << /R (00) /C 3 >> << /R (00) /C 3 >> << /R (00) /C 3 >> << /R (00) /C 3 >> << /R (00) /C 3 >> << /R (00) /C 3 >> << /R (00) /C 3 >> << /R (00) /C 3 >> << /R (00) /C 3 >> << /R (00) /C 3 >> << /R (00) /C 3 >> << /R (00) /C 3 >> << /R (00) /C 3 >> << /R (00) /C 3 >> << /R (00) /C 3 >> << /R (00) /C 3 >> << /R () /C 4 >> << /R () /C 4 >> << /R () /C 5 >> << /R (00) /C 5 >> << /R (  ) /C 5 >> << /R () /C 6 >> << /R (00) /C 6 >> << /R ( ) /C 7 >> << /R (00) /C 7 >> << /R (  ) /C 8 >> << /R ( % &) /C 8 >> << /R () /C 9 >> << /R () /C 9 >> << /R () /C 9 >> << /R () /C 10 >> << /R () /C 10 >> << /R () /C 10 >> << /R ( 0 0) /C 10 >> << /R ( 2 4) /C 10 >> << /R (00) /C 11 >> << /R (0B0B) /C 12 >> << /R (0D0D) /C 12 >> << /R (0F0F) /C 12 >> << /R (0H0H) /C 12 >> << /R (0J0b) /C 12 >> << /R (0d0) /C 12 >> << /R (00) /C 12 >> << /R (00) /C 12 >> << /R (00) /C 12 >> << /R () /C 13 >> << /R (00) /C 14 >> << /R (00) /C 14 >> << /R (00) /C 14 >> << /R (00) /C 14 >> << /R (00) /C 14 >> << /R (00) /C 14 >> << /R (00) /C 14 >> << /R (00) /C 14 >> << /R (00) /C 14 >> << /R (2 2C) /C 14 >> << /R (22) /C 14 >> << /R (22) /C 14 >> << /R (33W) /C 14 >> << /R (3q3v) /C 14 >> << /R (33) /C 14 >> << /R (N) /C 14 >> << /R (09) /C 15 >> << /R (!~) /C 16 >> << /R () /C 16 >> << /R (  ) /C 16 >> << /R (  ) /C 16 >> ] >> >> >> ] /DisplayList [ << /Resource 0 >> ] >> /MojiKumiTableSet << /Resources [ << /Resource << /Name (Photoshop6MojiKumiSet4) /Members << /CodeToClass 0 /AutoTsume << /TsumeMappings [ << /Before -.5 /Code () >> << /Before -.5 /Code (;) >> << /Before -.5 /Code ([) >> << /Before -.5 /Code ( ) >> << /Before -.5 /Code ( ) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0 ) >> << /Before -.5 /Code (0 ) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (=) >> << /After -.5 /Code (]) >> << /After -.5 /Code ( ) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0) >> << /After -.5 /Code (0) >> << /After -.5 /Code (0) >> << /After -.5 /Code () >> << /After -.5 /Code (0) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (0) >> << /Before -.25 /After -.25 /Code () >> << /Before -.25 /After -.25 /Code () >> << /Before -.25 /After -.25 /Code (0) >> << /Before -.25 /After -.25 /Code ( ) >> ] >> /Table << /DataArray << /SparseArray [ << /Index 1 /Elements [ << /P [ 1 5 ] /Data << /A << /R [ .25 .25 .25 ] /P 1 >> >> >> ] >> << /Index 2 /Elements [ << /P [ 2 1 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 2 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 3 >> >> >> << /P [ 2 3 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 4 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 5 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 2 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 2 8 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 9 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 10 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 11 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 3 >> >> >> << /P [ 2 12 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 13 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 14 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 15 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 16 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 17 ] /Data << /B << /R [ .5 .5 .5 ] >> >> >> ] >> << /Index 3 /Elements [ << /P [ 3 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 3 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 3 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 3 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 15 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 3 16 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 4 /Elements [ << /P [ 4 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 4 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 4 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 4 15 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 4 16 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> ] >> << /Index 5 /Elements [ << /P [ 5 1 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 2 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 3 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 4 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 5 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 1 >> >> >> << /P [ 5 6 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 7 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 8 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 9 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 10 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 11 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 12 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 13 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 14 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 15 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 16 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 17 ] /Data << /B << /R [ .25 .25 .25 ] >> >> >> ] >> << /Index 6 /Elements [ << /P [ 6 1 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 6 3 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 4 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 5 ] /Data << /B << /R [ 0.0 .75 .75 ] /P 1 >> >> >> << /P [ 6 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 6 8 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 9 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 10 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 11 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 12 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 13 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 14 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 15 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 4 >> >> >> << /P [ 6 16 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 4 >> >> >> << /P [ 6 17 ] /Data << /B << /R [ .5 .5 .5 ] >> >> >> ] >> << /Index 7 /Elements [ << /P [ 7 1 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 3 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 4 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 5 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 7 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 7 8 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 9 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 10 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 12 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 13 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 14 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 15 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 16 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 17 ] /Data << /B << /R [ .5 .5 .5 ] >> >> >> ] >> << /Index 8 /Elements [ << /P [ 8 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 8 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 8 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 8 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 8 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 9 /Elements [ << /P [ 9 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 9 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 9 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 9 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 9 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 10 /Elements [ << /P [ 10 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 10 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 10 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 10 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 10 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 11 /Elements [ << /P [ 11 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 11 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 11 15 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 4 >> >> >> << /P [ 11 16 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 4 >> >> >> ] >> << /Index 12 /Elements [ << /P [ 12 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 12 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 12 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 12 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 15 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 12 16 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 13 /Elements [ << /P [ 13 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 13 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 13 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 13 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 15 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 13 16 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 14 /Elements [ << /P [ 14 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 14 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 14 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 14 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 15 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 14 16 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 15 /Elements [ << /P [ 15 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 15 3 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 15 4 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 15 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 15 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 15 8 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 15 9 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 15 10 ] /Data << /A << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 15 12 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 15 14 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 16 /Elements [ << /P [ 16 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 16 3 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 16 4 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 16 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 16 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 16 8 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 16 9 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 16 10 ] /Data << /A << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 16 12 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 16 14 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 17 /Elements [ << /P [ 17 1 ] /Data << /A << /R [ .5 .5 .5 ] >> >> >> ] >> << /Index 18 /Elements [ << /P [ 18 1 ] /Data << /A << /R [ .5 .5 .5 ] >> >> >> ] >> ] >> >> /PredefinedTag 2 >> >> >> << /Resource << /Name (Photoshop6MojiKumiSet3) /Members << /CodeToClass 0 /AutoTsume << /TsumeMappings [ << /Before -.5 /Code () >> << /Before -.5 /Code (;) >> << /Before -.5 /Code ([) >> << /Before -.5 /Code ( ) >> << /Before -.5 /Code ( ) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0 ) >> << /Before -.5 /Code (0 ) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (=) >> << /After -.5 /Code (]) >> << /After -.5 /Code ( ) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0) >> << /After -.5 /Code (0) >> << /After -.5 /Code (0) >> << /After -.5 /Code () >> << /After -.5 /Code (0) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (0) >> << /Before -.25 /After -.25 /Code () >> << /Before -.25 /After -.25 /Code () >> << /Before -.25 /After -.25 /Code (0) >> << /Before -.25 /After -.25 /Code ( ) >> ] >> /Table << /DataArray << /SparseArray [ << /Index 1 /Elements [ << /P [ 1 5 ] /Data << /A << /R [ .25 .25 .25 ] /P 1 >> >> >> ] >> << /Index 2 /Elements [ << /P [ 2 1 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 2 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 3 >> >> >> << /P [ 2 3 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 4 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 5 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 2 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 2 8 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 9 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 10 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 11 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 3 >> >> >> << /P [ 2 12 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 13 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 14 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 15 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 16 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 17 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> ] >> << /Index 3 /Elements [ << /P [ 3 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 3 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 3 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 3 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 15 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 3 16 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 4 /Elements [ << /P [ 4 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 4 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 4 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 4 15 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 4 16 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> ] >> << /Index 5 /Elements [ << /P [ 5 1 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 2 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 3 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 4 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 5 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 1 >> >> >> << /P [ 5 6 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 7 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 8 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 9 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 10 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 11 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 12 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 13 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 14 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 15 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 16 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> ] >> << /Index 6 /Elements [ << /P [ 6 1 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 6 3 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 4 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 5 ] /Data << /B << /R [ 0.0 .75 .75 ] /P 1 >> >> >> << /P [ 6 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 6 8 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 9 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 10 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 11 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 12 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 13 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 14 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 15 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 4 >> >> >> << /P [ 6 16 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 4 >> >> >> << /P [ 6 17 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> ] >> << /Index 7 /Elements [ << /P [ 7 1 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 3 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 4 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 5 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 7 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 7 8 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 9 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 10 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 12 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 13 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 14 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 15 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 16 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 17 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> ] >> << /Index 8 /Elements [ << /P [ 8 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 8 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 8 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 8 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 8 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 9 /Elements [ << /P [ 9 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 9 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 9 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 9 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 9 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 10 /Elements [ << /P [ 10 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 10 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 10 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 10 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 10 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 11 /Elements [ << /P [ 11 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 11 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 11 15 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 4 >> >> >> << /P [ 11 16 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 4 >> >> >> ] >> << /Index 12 /Elements [ << /P [ 12 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 12 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 12 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 12 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 15 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 12 16 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 13 /Elements [ << /P [ 13 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 13 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 13 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 13 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 15 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 13 16 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 14 /Elements [ << /P [ 14 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 14 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 14 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 14 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 15 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 14 16 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 15 /Elements [ << /P [ 15 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 15 3 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 15 4 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 15 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 15 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 15 8 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 15 9 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 15 10 ] /Data << /A << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 15 12 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 15 14 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 16 /Elements [ << /P [ 16 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 16 3 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 16 4 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 16 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 16 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 16 8 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 16 9 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 16 10 ] /Data << /A << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 16 12 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 16 14 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> ] >> >> /PredefinedTag 4 >> >> >> << /Resource << /Name (Photoshop6MojiKumiSet2) /Members << /CodeToClass 0 /AutoTsume << /TsumeMappings [ << /Before -.5 /Code () >> << /Before -.5 /Code (;) >> << /Before -.5 /Code ([) >> << /Before -.5 /Code ( ) >> << /Before -.5 /Code ( ) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0 ) >> << /Before -.5 /Code (0 ) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (=) >> << /After -.5 /Code (]) >> << /After -.5 /Code ( ) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0) >> << /After -.5 /Code (0) >> << /After -.5 /Code (0) >> << /After -.5 /Code () >> << /After -.5 /Code (0) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (0) >> << /Before -.25 /After -.25 /Code () >> << /Before -.25 /After -.25 /Code () >> << /Before -.25 /After -.25 /Code (0) >> << /Before -.25 /After -.25 /Code ( ) >> ] >> /Table << /DataArray << /SparseArray [ << /Index 1 /Elements [ << /P [ 1 5 ] /Data << /A << /R [ .25 .25 .25 ] /P 1 >> >> >> ] >> << /Index 2 /Elements [ << /P [ 2 1 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 2 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 3 >> >> >> << /P [ 2 3 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 4 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 5 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 2 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 2 8 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 9 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 10 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 11 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 3 >> >> >> << /P [ 2 12 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 13 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 14 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 15 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 16 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> ] >> << /Index 3 /Elements [ << /P [ 3 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 3 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 3 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 3 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 15 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 3 16 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 4 /Elements [ << /P [ 4 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 4 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 4 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 4 15 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 4 16 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> ] >> << /Index 5 /Elements [ << /P [ 5 1 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 2 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 3 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 4 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 5 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 1 >> >> >> << /P [ 5 6 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 7 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 8 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 9 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 10 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 11 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 12 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 13 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 14 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 15 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 16 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> ] >> << /Index 6 /Elements [ << /P [ 6 1 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 6 3 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 4 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 5 ] /Data << /B << /R [ 0.0 .75 .75 ] /P 1 >> >> >> << /P [ 6 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 6 8 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 9 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 10 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 11 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 12 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 13 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 14 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 15 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 4 >> >> >> << /P [ 6 16 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 4 >> >> >> ] >> << /Index 7 /Elements [ << /P [ 7 1 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 3 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 4 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 5 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 7 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 7 8 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 9 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 10 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 12 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 13 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 14 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 15 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 16 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> ] >> << /Index 8 /Elements [ << /P [ 8 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 8 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 8 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 8 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 8 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 9 /Elements [ << /P [ 9 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 9 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 9 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 9 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 9 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 10 /Elements [ << /P [ 10 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 10 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 10 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 10 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 10 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 11 /Elements [ << /P [ 11 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 11 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 11 15 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 4 >> >> >> << /P [ 11 16 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 4 >> >> >> ] >> << /Index 12 /Elements [ << /P [ 12 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 12 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 12 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 12 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 15 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 12 16 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 13 /Elements [ << /P [ 13 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 13 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 13 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 13 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 13 16 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 14 /Elements [ << /P [ 14 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 14 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 14 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 14 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 15 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 14 16 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 15 /Elements [ << /P [ 15 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 15 3 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 15 4 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 15 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 15 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 15 8 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 15 9 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 15 10 ] /Data << /A << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 15 12 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 15 14 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 16 /Elements [ << /P [ 16 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 16 3 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 16 4 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 16 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 16 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 16 8 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 16 9 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 16 10 ] /Data << /A << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 16 12 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 16 14 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> ] >> >> /PredefinedTag 3 >> >> >> << /Resource << /Name (Photoshop6MojiKumiSet1) /Members << /CodeToClass 0 /AutoTsume << /TsumeMappings [ << /Before -.5 /Code () >> << /Before -.5 /Code (;) >> << /Before -.5 /Code ([) >> << /Before -.5 /Code ( ) >> << /Before -.5 /Code ( ) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0 ) >> << /Before -.5 /Code (0 ) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (=) >> << /After -.5 /Code (]) >> << /After -.5 /Code ( ) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0) >> << /After -.5 /Code (0) >> << /After -.5 /Code (0) >> << /After -.5 /Code () >> << /After -.5 /Code (0) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (0) >> << /Before -.25 /After -.25 /Code () >> << /Before -.25 /After -.25 /Code () >> << /Before -.25 /After -.25 /Code (0) >> << /Before -.25 /After -.25 /Code ( ) >> ] >> /Table << /DataArray << /SparseArray [ << /Index 1 /Elements [ << /P [ 1 5 ] /Data << /A << /R [ .25 .25 .25 ] /P 1 >> >> >> ] >> << /Index 2 /Elements [ << /P [ 2 1 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 2 2 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 3 >> >> >> << /P [ 2 3 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 2 4 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 2 5 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 2 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 2 8 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 3 >> >> >> << /P [ 2 9 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 2 10 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 2 11 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 3 >> >> >> << /P [ 2 12 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 2 13 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 2 14 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 2 15 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 2 16 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> ] >> << /Index 3 /Elements [ << /P [ 3 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 3 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 3 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 3 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 15 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 3 16 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 4 /Elements [ << /P [ 4 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 4 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 4 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 4 15 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 4 16 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> ] >> << /Index 5 /Elements [ << /P [ 5 1 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 2 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 3 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 4 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 5 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 1 >> >> >> << /P [ 5 6 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 7 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 8 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 9 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 10 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 11 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 12 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 13 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 14 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 15 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 16 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> ] >> << /Index 6 /Elements [ << /P [ 6 1 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 6 3 ] /Data << /B << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 6 4 ] /Data << /B << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 6 5 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 6 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 6 8 ] /Data << /B << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 6 9 ] /Data << /B << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 6 10 ] /Data << /B << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 6 11 ] /Data << /B << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 6 12 ] /Data << /B << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 6 13 ] /Data << /B << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 6 14 ] /Data << /B << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 6 15 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 6 16 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 7 /Elements [ << /P [ 7 1 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 3 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 4 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 5 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 7 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 7 8 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 9 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 10 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 12 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 13 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 14 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 15 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 16 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> ] >> << /Index 8 /Elements [ << /P [ 8 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 8 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 8 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 8 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 8 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 9 /Elements [ << /P [ 9 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 9 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 9 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 9 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 9 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 10 /Elements [ << /P [ 10 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 10 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 10 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 10 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 10 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 11 /Elements [ << /P [ 11 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 11 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 11 15 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 4 >> >> >> << /P [ 11 16 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 4 >> >> >> ] >> << /Index 12 /Elements [ << /P [ 12 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 12 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 12 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 12 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 15 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 12 16 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 13 /Elements [ << /P [ 13 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 13 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 13 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 13 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 15 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 13 16 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 14 /Elements [ << /P [ 14 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 14 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 14 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 14 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 15 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 14 16 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 15 /Elements [ << /P [ 15 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 15 3 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 15 4 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 15 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 15 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 15 8 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 15 9 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 15 10 ] /Data << /A << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 15 12 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 15 14 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 16 /Elements [ << /P [ 16 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 16 3 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 16 4 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 16 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 16 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 16 8 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 16 9 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 16 10 ] /Data << /A << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 16 12 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 16 14 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> ] >> >> /PredefinedTag 1 >> >> >> << /Resource << /Name (YakumonoHankaku) /Members << /CodeToClass 0 /AutoTsume << /TsumeMappings [ << /Before -.5 /Code () >> << /Before -.5 /Code (;) >> << /Before -.5 /Code ([) >> << /Before -.5 /Code ( ) >> << /Before -.5 /Code ( ) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0 ) >> << /Before -.5 /Code (0 ) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (=) >> << /After -.5 /Code (]) >> << /After -.5 /Code ( ) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0) >> << /After -.5 /Code (0) >> << /After -.5 /Code (0) >> << /After -.5 /Code () >> << /After -.5 /Code (0) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (0) >> << /Before -.25 /After -.25 /Code () >> << /Before -.25 /After -.25 /Code () >> << /Before -.25 /After -.25 /Code (0) >> << /Before -.25 /After -.25 /Code ( ) >> ] >> /Table << /DataArray << /SparseArray [ << /Index 1 /Elements [ << /P [ 1 5 ] /Data << /A << /R [ .25 .25 .25 ] /P 1 >> >> >> ] >> << /Index 2 /Elements [ << /P [ 2 1 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 2 2 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 3 >> >> >> << /P [ 2 3 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 2 4 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 2 5 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 2 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 2 8 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 3 >> >> >> << /P [ 2 9 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 2 10 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 2 11 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 3 >> >> >> << /P [ 2 12 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 2 13 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 2 14 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 2 15 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 2 16 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> ] >> << /Index 3 /Elements [ << /P [ 3 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 3 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 3 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 3 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 15 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 3 16 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 4 /Elements [ << /P [ 4 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 4 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 4 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 4 15 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 4 16 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> ] >> << /Index 5 /Elements [ << /P [ 5 1 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 2 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 3 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 4 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 5 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 1 >> >> >> << /P [ 5 6 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 7 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 8 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 9 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 10 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 11 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 12 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 13 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 14 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 15 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 16 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> ] >> << /Index 6 /Elements [ << /P [ 6 1 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 6 3 ] /Data << /B << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 6 4 ] /Data << /B << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 6 5 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 6 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 6 8 ] /Data << /B << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 6 9 ] /Data << /B << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 6 10 ] /Data << /B << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 6 11 ] /Data << /B << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 6 12 ] /Data << /B << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 6 13 ] /Data << /B << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 6 14 ] /Data << /B << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 6 15 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 6 16 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 7 /Elements [ << /P [ 7 1 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 3 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 4 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 5 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 7 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 7 8 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 9 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 10 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 12 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 13 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 14 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 15 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> << /P [ 7 16 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 2 >> >> >> ] >> << /Index 8 /Elements [ << /P [ 8 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 8 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 8 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 8 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 8 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 9 /Elements [ << /P [ 9 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 9 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 9 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 9 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 9 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 10 /Elements [ << /P [ 10 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 10 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 10 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 10 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 10 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 11 /Elements [ << /P [ 11 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 11 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 11 15 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 4 >> >> >> << /P [ 11 16 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 4 >> >> >> ] >> << /Index 12 /Elements [ << /P [ 12 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 12 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 12 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 12 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 15 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 12 16 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 13 /Elements [ << /P [ 13 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 13 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 13 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 13 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 15 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 13 16 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 14 /Elements [ << /P [ 14 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 14 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 14 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 14 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 15 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 14 16 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 15 /Elements [ << /P [ 15 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 15 3 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 15 4 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 15 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 15 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 15 8 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 15 9 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 15 10 ] /Data << /A << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 15 12 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 15 14 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 16 /Elements [ << /P [ 16 1 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 3 >> >> >> << /P [ 16 3 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 16 4 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 16 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 16 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 16 8 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 16 9 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 16 10 ] /Data << /A << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 16 12 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 16 14 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> ] >> >> /PredefinedTag 1 >> >> >> << /Resource << /Name (GyomatsuYakumonoHankaku) /Members << /CodeToClass 0 /AutoTsume << /TsumeMappings [ << /Before -.5 /Code () >> << /Before -.5 /Code (;) >> << /Before -.5 /Code ([) >> << /Before -.5 /Code ( ) >> << /Before -.5 /Code ( ) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0 ) >> << /Before -.5 /Code (0 ) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (=) >> << /After -.5 /Code (]) >> << /After -.5 /Code ( ) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0) >> << /After -.5 /Code (0) >> << /After -.5 /Code (0) >> << /After -.5 /Code () >> << /After -.5 /Code (0) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (0) >> << /Before -.25 /After -.25 /Code () >> << /Before -.25 /After -.25 /Code () >> << /Before -.25 /After -.25 /Code (0) >> << /Before -.25 /After -.25 /Code ( ) >> ] >> /Table << /DataArray << /SparseArray [ << /Index 1 /Elements [ << /P [ 1 5 ] /Data << /A << /R [ .25 .25 .25 ] /P 1 >> >> >> ] >> << /Index 2 /Elements [ << /P [ 2 1 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 2 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 3 >> >> >> << /P [ 2 3 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 4 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 5 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 2 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 2 8 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 9 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 10 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 11 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 3 >> >> >> << /P [ 2 12 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 13 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 14 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 15 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 16 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> ] >> << /Index 3 /Elements [ << /P [ 3 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 3 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 3 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 3 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 15 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 3 16 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 4 /Elements [ << /P [ 4 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 4 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 4 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 4 15 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 4 16 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> ] >> << /Index 5 /Elements [ << /P [ 5 1 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 2 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 3 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 4 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 5 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 1 >> >> >> << /P [ 5 6 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 7 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 8 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 9 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 10 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 11 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 12 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 13 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 14 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 15 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 16 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> ] >> << /Index 6 /Elements [ << /P [ 6 1 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 6 3 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 4 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 5 ] /Data << /B << /R [ 0.0 .75 .75 ] /P 1 >> >> >> << /P [ 6 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 6 8 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 9 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 10 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 11 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 12 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 13 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 14 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 15 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 4 >> >> >> << /P [ 6 16 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 4 >> >> >> ] >> << /Index 7 /Elements [ << /P [ 7 1 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 3 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 4 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 5 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 7 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 7 8 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 9 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 10 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 12 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 13 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 14 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 15 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 16 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> ] >> << /Index 8 /Elements [ << /P [ 8 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 8 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 8 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 8 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 8 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 9 /Elements [ << /P [ 9 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 9 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 9 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 9 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 9 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 10 /Elements [ << /P [ 10 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 10 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 10 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 10 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 10 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 11 /Elements [ << /P [ 11 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 11 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 11 15 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 4 >> >> >> << /P [ 11 16 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 4 >> >> >> ] >> << /Index 12 /Elements [ << /P [ 12 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 12 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 12 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 12 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 15 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 12 16 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 13 /Elements [ << /P [ 13 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 13 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 13 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 13 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 13 16 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 14 /Elements [ << /P [ 14 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 14 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 14 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 14 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 15 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 14 16 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 15 /Elements [ << /P [ 15 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 15 3 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 15 4 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 15 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 15 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 15 8 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 15 9 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 15 10 ] /Data << /A << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 15 12 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 15 14 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 16 /Elements [ << /P [ 16 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 16 3 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 16 4 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 16 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 16 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 16 8 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 16 9 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 16 10 ] /Data << /A << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 16 12 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 16 14 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> ] >> >> /PredefinedTag 3 >> >> >> << /Resource << /Name (GyomatsuYakumonoZenkaku) /Members << /CodeToClass 0 /AutoTsume << /TsumeMappings [ << /Before -.5 /Code () >> << /Before -.5 /Code (;) >> << /Before -.5 /Code ([) >> << /Before -.5 /Code ( ) >> << /Before -.5 /Code ( ) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0 ) >> << /Before -.5 /Code (0 ) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (=) >> << /After -.5 /Code (]) >> << /After -.5 /Code ( ) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0) >> << /After -.5 /Code (0) >> << /After -.5 /Code (0) >> << /After -.5 /Code () >> << /After -.5 /Code (0) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (0) >> << /Before -.25 /After -.25 /Code () >> << /Before -.25 /After -.25 /Code () >> << /Before -.25 /After -.25 /Code (0) >> << /Before -.25 /After -.25 /Code ( ) >> ] >> /Table << /DataArray << /SparseArray [ << /Index 1 /Elements [ << /P [ 1 5 ] /Data << /A << /R [ .25 .25 .25 ] /P 1 >> >> >> ] >> << /Index 2 /Elements [ << /P [ 2 1 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 2 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 3 >> >> >> << /P [ 2 3 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 4 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 5 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 2 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 2 8 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 9 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 10 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 11 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 3 >> >> >> << /P [ 2 12 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 13 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 14 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 15 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 16 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 17 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> ] >> << /Index 3 /Elements [ << /P [ 3 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 3 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 3 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 3 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 15 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 3 16 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 4 /Elements [ << /P [ 4 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 4 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 4 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 4 15 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 4 16 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> ] >> << /Index 5 /Elements [ << /P [ 5 1 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 2 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 3 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 4 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 5 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 1 >> >> >> << /P [ 5 6 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 7 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 8 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 9 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 10 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 11 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 12 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 13 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 14 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 15 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 16 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> ] >> << /Index 6 /Elements [ << /P [ 6 1 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 6 3 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 4 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 5 ] /Data << /B << /R [ 0.0 .75 .75 ] /P 1 >> >> >> << /P [ 6 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 6 8 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 9 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 10 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 11 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 12 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 13 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 14 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 15 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 4 >> >> >> << /P [ 6 16 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 4 >> >> >> << /P [ 6 17 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> ] >> << /Index 7 /Elements [ << /P [ 7 1 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 3 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 4 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 5 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 7 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 7 8 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 9 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 10 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 12 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 13 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 14 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 15 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 16 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 17 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> ] >> << /Index 8 /Elements [ << /P [ 8 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 8 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 8 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 8 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 8 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 9 /Elements [ << /P [ 9 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 9 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 9 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 9 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 9 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 10 /Elements [ << /P [ 10 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 10 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 10 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 10 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 10 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 11 /Elements [ << /P [ 11 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 11 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 11 15 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 4 >> >> >> << /P [ 11 16 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 4 >> >> >> ] >> << /Index 12 /Elements [ << /P [ 12 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 12 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 12 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 12 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 15 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 12 16 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 13 /Elements [ << /P [ 13 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 13 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 13 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 13 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 15 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 13 16 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 14 /Elements [ << /P [ 14 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 14 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 14 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 14 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 15 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 14 16 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 15 /Elements [ << /P [ 15 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 15 3 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 15 4 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 15 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 15 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 15 8 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 15 9 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 15 10 ] /Data << /A << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 15 12 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 15 14 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 16 /Elements [ << /P [ 16 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 16 3 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 16 4 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 16 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 16 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 16 8 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 16 9 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 16 10 ] /Data << /A << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 16 12 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 16 14 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> ] >> >> /PredefinedTag 4 >> >> >> << /Resource << /Name (YakumonoZenkaku) /Members << /CodeToClass 0 /AutoTsume << /TsumeMappings [ << /Before -.5 /Code () >> << /Before -.5 /Code (;) >> << /Before -.5 /Code ([) >> << /Before -.5 /Code ( ) >> << /Before -.5 /Code ( ) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0 ) >> << /Before -.5 /Code (0 ) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0) >> << /Before -.5 /Code (0) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (=) >> << /After -.5 /Code (]) >> << /After -.5 /Code ( ) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0 ) >> << /After -.5 /Code (0) >> << /After -.5 /Code (0) >> << /After -.5 /Code (0) >> << /After -.5 /Code () >> << /After -.5 /Code (0) >> << /After -.5 /Code ( ) >> << /After -.5 /Code (0) >> << /Before -.25 /After -.25 /Code () >> << /Before -.25 /After -.25 /Code () >> << /Before -.25 /After -.25 /Code (0) >> << /Before -.25 /After -.25 /Code ( ) >> ] >> /Table << /DataArray << /SparseArray [ << /Index 1 /Elements [ << /P [ 1 5 ] /Data << /A << /R [ .25 .25 .25 ] /P 1 >> >> >> ] >> << /Index 2 /Elements [ << /P [ 2 1 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 2 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 3 >> >> >> << /P [ 2 3 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 4 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 5 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 2 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 2 8 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 9 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 10 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 11 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 3 >> >> >> << /P [ 2 12 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 13 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 14 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 15 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 16 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 2 17 ] /Data << /B << /R [ .5 .5 .5 ] >> >> >> ] >> << /Index 3 /Elements [ << /P [ 3 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 3 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 3 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 3 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 3 15 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 3 16 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 4 /Elements [ << /P [ 4 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 4 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 4 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 4 15 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 4 16 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> ] >> << /Index 5 /Elements [ << /P [ 5 1 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 2 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 3 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 4 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 5 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 1 >> >> >> << /P [ 5 6 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 7 ] /Data << /B << /R [ .25 .25 .25 ] /P 1 >> >> >> << /P [ 5 8 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 9 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 10 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 11 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 12 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 13 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 14 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 15 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 16 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 5 17 ] /Data << /B << /R [ .25 .25 .25 ] >> >> >> ] >> << /Index 6 /Elements [ << /P [ 6 1 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 6 3 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 4 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 5 ] /Data << /B << /R [ 0.0 .75 .75 ] /P 1 >> >> >> << /P [ 6 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 6 8 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 9 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 10 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 11 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 12 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 13 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 14 ] /Data << /B << /R [ 0.0 .5 .5 ] >> >> >> << /P [ 6 15 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 4 >> >> >> << /P [ 6 16 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 4 >> >> >> << /P [ 6 17 ] /Data << /B << /R [ .5 .5 .5 ] >> >> >> ] >> << /Index 7 /Elements [ << /P [ 7 1 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 3 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 4 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 5 ] /Data << /B << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 7 7 ] /Data << /B << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 7 8 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 9 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 10 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 12 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 13 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 14 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 15 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 16 ] /Data << /B << /R [ 0.0 .5 .5 ] /P 2 >> >> >> << /P [ 7 17 ] /Data << /B << /R [ .5 .5 .5 ] >> >> >> ] >> << /Index 8 /Elements [ << /P [ 8 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 8 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 8 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 8 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 8 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 8 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 9 /Elements [ << /P [ 9 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 9 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 9 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 9 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 9 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 9 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 10 /Elements [ << /P [ 10 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 10 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 10 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 10 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 10 15 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 10 16 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 11 /Elements [ << /P [ 11 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 11 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 11 15 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 4 >> >> >> << /P [ 11 16 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 4 >> >> >> ] >> << /Index 12 /Elements [ << /P [ 12 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 12 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 12 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 12 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 12 15 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 12 16 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 13 /Elements [ << /P [ 13 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 13 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 13 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 13 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 13 15 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 13 16 ] /Data << /B << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> ] >> << /Index 14 /Elements [ << /P [ 14 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 14 3 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 14 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 14 8 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 9 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 10 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 12 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 13 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 14 ] /Data << /A << /R [ 0.0 0.0 1.0 ] >> >> >> << /P [ 14 15 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 14 16 ] /Data << /B << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 15 /Elements [ << /P [ 15 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 15 3 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 15 4 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 15 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 15 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 15 8 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 15 9 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 15 10 ] /Data << /A << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 15 12 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 15 14 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 16 /Elements [ << /P [ 16 1 ] /Data << /A << /R [ 0.0 .5 .5 ] /P 3 >> >> >> << /P [ 16 3 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 16 4 ] /Data << /A << /R [ .125 .25 .25 ] /P 4 >> >> >> << /P [ 16 5 ] /Data << /A << /R [ 0.0 .25 .25 ] /P 1 >> >> >> << /P [ 16 7 ] /Data << /A << /R [ 0.0 0.0 0.0 ] /P 2 >> >> >> << /P [ 16 8 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 16 9 ] /Data << /A << /R [ 0.0 0.0 .5 ] /P 4 >> >> >> << /P [ 16 10 ] /Data << /A << /R [ 0.0 0.0 .5 ] >> >> >> << /P [ 16 12 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> << /P [ 16 14 ] /Data << /A << /R [ .125 .25 .5 ] /P 4 >> >> >> ] >> << /Index 17 /Elements [ << /P [ 17 1 ] /Data << /A << /R [ .5 .5 .5 ] >> >> >> ] >> << /Index 18 /Elements [ << /P [ 18 1 ] /Data << /A << /R [ .5 .5 .5 ] >> >> >> ] >> ] >> >> /PredefinedTag 2 >> >> >> ] /DisplayList [ << /Resource 0 >> << /Resource 1 >> << /Resource 2 >> << /Resource 3 >> << /Resource 4 >> << /Resource 5 >> << /Resource 6 >> << /Resource 7 >> ] >> /KinsokuSet << /Resources [ << /Resource << /Name (None) /Data << /NoStart () /NoEnd () /Keep () /Hanging () /PredefinedTag 0 >> >> >> << /Resource << /Name (PhotoshopKinsokuHard) /Data << /NoStart (!\),.:;?]}    0!! 0000 0 0 0000A0C0E0G0I0c000000000000000000000000 =]) /NoEnd (\([{  00 0 0000 ;[) /Keep (  % &) /Hanging (00 ) /PredefinedTag 1 >> >> >> << /Resource << /Name (PhotoshopKinsokuSoft) /Data << /NoStart (  0000 0 0 00000000 =]) /NoEnd (  00 0 000;[) /Keep (  % &) /Hanging (00 ) /PredefinedTag 2 >> >> >> << /Resource << /Name (Hard) /Data << /NoStart (!\),.:;?]}    0!! 0000 0 0 0000A0C0E0G0I0c000000000000000000000000 =]) /NoEnd (\([{  00 0 0000 ;[) /Keep (  % &) /Hanging (00 ) /PredefinedTag 1 >> >> >> << /Resource << /Name (Soft) /Data << /NoStart (  0000 0 0 00000000 =]) /NoEnd (  00 0 000;[) /Keep (  % &) /Hanging (00 ) /PredefinedTag 2 >> >> >> ] /DisplayList [ << /Resource 0 >> << /Resource 1 >> << /Resource 2 >> << /Resource 3 >> << /Resource 4 >> ] >> /StyleSheetSet << /Resources [ << /Resource << /Name (Normal RGB) /Features << /Font 3 /FontSize 12.0 /FauxBold false /FauxItalic false /AutoLeading true /Leading 0.0 /HorizontalScale 1.0 /VerticalScale 1.0 /Tracking 0 /BaselineShift 0.0 /CharacterRotation 0.0 /AutoKern 1 /FontCaps 0 /FontBaseline 0 /FontOTPosition 0 /StrikethroughPosition 0 /UnderlinePosition 0 /UnderlineOffset 0.0 /Ligatures true /DiscretionaryLigatures false /ContextualLigatures false /AlternateLigatures false /OldStyle false /Fractions false /Ordinals false /Swash false /Titling false /ConnectionForms false /StylisticAlternates false /Ornaments false /FigureStyle 0 /ProportionalMetrics false /Kana false /Italics false /Ruby false /BaselineDirection 2 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /JapaneseAlternateFeature 0 /EnableWariChu false /WariChuLineCount 2 /WariChuLineGap 0 /WariChuSubLineAmount << /WariChuSubLineScale .5 >> /WariChuWidowAmount 2 /WariChuOrphanAmount 2 /WariChuJustification 7 /TCYUpDownAdjustment 0 /TCYLeftRightAdjustment 0 /LeftAki -1.0 /RightAki -1.0 /JiDori 0 /NoBreak false /FillColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> >> /StrokeColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> >> /Blend << /StreamTag /SimpleBlender >> /FillFlag true /StrokeFlag false /FillFirst true /FillOverPrint false /StrokeOverPrint false /LineCap 0 /LineJoin 0 /LineWidth 1.0 /MiterLimit 4.0 /LineDashOffset 0.0 /LineDashArray [ ] /Type1EncodingNames [ ] /Kashidas 0 /DirOverride 0 /DigitSet 0 /DiacVPos 4 /DiacXOffset 0.0 /DiacYOffset 0.0 /OverlapSwash false /JustificationAlternates false /StretchedAlternates false /FillVisibleFlag true /StrokeVisibleFlag true >> >> >> ] /DisplayList [ << /Resource 0 >> ] >> /ParagraphSheetSet << /Resources [ << /Resource << /Name (Normal RGB) /Features << /Justification 0 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /DropCaps 1 /AutoLeading 1.2 /LeadingType 0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 0 /Zone 36.0 /HyphenateCapitalized true /HyphenationPreference .5 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /SingleWordJustification 6 /Hanging false /AutoTCY 0 /KeepTogether true /BurasagariType 0 /KinsokuOrder 0 /Kinsoku /nil /KurikaeshiMojiShori false /MojiKumiTable /nil /EveryLineComposer false /TabStops << >> /DefaultTabWidth 36.0 /DefaultStyle << >> /ParagraphDirection 0 /JustificationMethod 0 /ComposerEngine 0 >> >> >> ] /DisplayList [ << /Resource 0 >> ] >> /TextFrameSet << /Resources [ << /Resource << /Bezier << /Points [ 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ] >> /Data << /Type 0 /LineOrientation 0 /TextOnPathTRange [ -1.0 -1.0 ] /RowGutter 0.0 /ColumnGutter 0.0 /FirstBaselineAlignment << /Flag 1 /Min 0.0 >> /PathData << /Spacing -1 >> >> >> >> << /Resource << /Bezier << /Points [ 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ] >> /Data << /Type 0 /LineOrientation 0 /TextOnPathTRange [ -1.0 -1.0 ] /RowGutter 0.0 /ColumnGutter 0.0 /FirstBaselineAlignment << /Flag 1 /Min 0.0 >> /PathData << /Spacing -1 >> >> >> >> << /Resource << /Bezier << /Points [ 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ] >> /Data << /Type 0 /LineOrientation 0 /TextOnPathTRange [ -1.0 -1.0 ] /RowGutter 0.0 /ColumnGutter 0.0 /FirstBaselineAlignment << /Flag 1 /Min 0.0 >> /PathData << /Spacing -1 >> >> >> >> << /Resource << /Bezier << /Points [ 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ] >> /Data << /Type 0 /LineOrientation 0 /TextOnPathTRange [ -1.0 -1.0 ] /RowGutter 0.0 /ColumnGutter 0.0 /FirstBaselineAlignment << /Flag 1 /Min 0.0 >> /PathData << /Spacing -1 >> >> >> >> << /Resource << /Bezier << /Points [ 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 ] >> /Data << /Type 0 /LineOrientation 0 /TextOnPathTRange [ -1.0 -1.0 ] /RowGutter 0.0 /ColumnGutter 0.0 /FirstBaselineAlignment << /Flag 1 /Min 0.0 >> /PathData << /Spacing -1 >> >> >> >> ] >> >> /DocumentObjects << /DocumentSettings << /HiddenGlyphFont << /AlternateGlyphFont 4 /WhitespaceCharacterMapping [ << /WhitespaceCharacter ( ) /AlternateCharacter (1) >> << /WhitespaceCharacter ( ) /AlternateCharacter (6) >> << /WhitespaceCharacter ( ) /AlternateCharacter (0) >> << /WhitespaceCharacter ( \)) /AlternateCharacter (5) >> << /WhitespaceCharacter () /AlternateCharacter (5) >> << /WhitespaceCharacter (0) /AlternateCharacter (1) >> << /WhitespaceCharacter () /AlternateCharacter (3) >> ] >> /NormalStyleSheet 0 /NormalParagraphSheet 0 /SuperscriptSize .583 /SuperscriptPosition .333 /SubscriptSize .583 /SubscriptPosition .333 /SmallCapSize .7 /UseSmartQuotes true /SmartQuoteSets [ << /Language 0 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 1 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 2 /OpenDoubleQuote () /CloseDoubleQuote () /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 3 /OpenDoubleQuote () /CloseDoubleQuote () /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 4 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 5 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 6 /OpenDoubleQuote () /CloseDoubleQuote () /OpenSingleQuote ( 9) /CloseSingleQuote ( :) >> << /Language 7 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 8 /OpenDoubleQuote () /CloseDoubleQuote () /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 9 /OpenDoubleQuote () /CloseDoubleQuote () /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 10 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 11 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 12 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 13 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 14 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 15 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 16 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 17 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 18 /OpenDoubleQuote () /CloseDoubleQuote () /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 19 /OpenDoubleQuote () /CloseDoubleQuote () /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 20 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 21 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 22 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 23 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 24 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 25 /OpenDoubleQuote () /CloseDoubleQuote () /OpenSingleQuote ( 9) /CloseSingleQuote ( :) >> << /Language 26 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 27 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 28 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 29 /OpenDoubleQuote (0) /CloseDoubleQuote (0) >> << /Language 30 /OpenDoubleQuote (0 ) /CloseDoubleQuote (0 ) >> << /Language 31 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 32 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 33 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 34 /OpenDoubleQuote () /CloseDoubleQuote () /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 35 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 36 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 37 /OpenDoubleQuote () /CloseDoubleQuote () /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 38 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 39 /OpenDoubleQuote () /CloseDoubleQuote () /OpenSingleQuote (<) /CloseSingleQuote (>) >> << /Language 40 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 41 /OpenDoubleQuote () /CloseDoubleQuote () /OpenSingleQuote (<) /CloseSingleQuote (>) >> << /Language 42 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 43 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> << /Language 44 /OpenDoubleQuote () /CloseDoubleQuote () /OpenSingleQuote ( 9) /CloseSingleQuote ( :) >> << /Language 45 /OpenDoubleQuote ( ) /CloseDoubleQuote ( ) /OpenSingleQuote ( ) /CloseSingleQuote ( ) >> ] >> /TextObjects [ << /Model << /Text (} ) /ParagraphRun << /RunArray [ << /RunData << /ParagraphSheet << /Name () /Features << /Justification 1 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /DropCaps 1 /AutoLeading 1.2 /LeadingType 0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /HyphenateCapitalized true /HyphenationPreference .5 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /SingleWordJustification 6 /Hanging false /AutoTCY 1 /KeepTogether true /BurasagariType 0 /KinsokuOrder 0 /Kinsoku /nil /KurikaeshiMojiShori false /MojiKumiTable /nil /EveryLineComposer false /TabStops << >> /DefaultTabWidth 36.0 /DefaultStyle << /Font 0 /FontSize 12.0 /FauxBold false /FauxItalic false /AutoLeading true /Leading 0.0 /HorizontalScale 1.0 /VerticalScale 1.0 /Tracking 0 /BaselineShift 0.0 /CharacterRotation 0.0 /AutoKern 1 /FontCaps 0 /FontBaseline 0 /FontOTPosition 0 /StrikethroughPosition 0 /UnderlinePosition 0 /UnderlineOffset 0.0 /Ligatures true /DiscretionaryLigatures false /ContextualLigatures false /AlternateLigatures false /OldStyle false /Fractions false /Ordinals false /Swash false /Titling false /ConnectionForms false /StylisticAlternates false /Ornaments false /FigureStyle 0 /ProportionalMetrics false /Kana false /Italics false /Ruby false /BaselineDirection 2 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /EnableWariChu false /WariChuLineCount 2 /WariChuLineGap 0 /WariChuSubLineAmount << /WariChuSubLineScale .5 >> /WariChuWidowAmount 2 /WariChuOrphanAmount 2 /WariChuJustification 7 /TCYUpDownAdjustment 0 /TCYLeftRightAdjustment 0 /LeftAki -1.0 /RightAki -1.0 /JiDori 0 /NoBreak false /FillColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> >> /StrokeColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> >> /FillFlag true /StrokeFlag false /FillFirst true /FillOverPrint false /StrokeOverPrint false /LineCap 0 /LineJoin 0 /LineWidth 1.0 /MiterLimit 4.0 /LineDashOffset 0.0 /LineDashArray [ ] /Type1EncodingNames [ ] /Kashidas 0 /DirOverride 0 /DigitSet 0 /DiacVPos 4 /DiacXOffset 0.0 /DiacYOffset 0.0 /OverlapSwash false /JustificationAlternates false /StretchedAlternates false /FillVisibleFlag true /StrokeVisibleFlag true >> /ParagraphDirection 0 /JustificationMethod 0 /ComposerEngine 0 >> /Parent 0 >> >> /Length 2 >> ] >> /StyleRun << /RunArray [ << /RunData << /StyleSheet << /Name () /Parent 0 /Features << /Font 2 /FontSize 200.0 /FauxBold true /FauxItalic false /AutoLeading true /Leading 240.00002 /HorizontalScale 1.0 /VerticalScale 1.2 /Tracking 0 /BaselineShift 0.0 /CharacterRotation 0.0 /AutoKern 0 /FontCaps 0 /FontBaseline 0 /FontOTPosition 0 /StrikethroughPosition 0 /UnderlinePosition 0 /UnderlineOffset 0.0 /Ligatures true /DiscretionaryLigatures false /ContextualLigatures false /AlternateLigatures false /OldStyle false /Fractions false /Ordinals false /Swash false /Titling false /ConnectionForms false /StylisticAlternates false /Ornaments false /FigureStyle 0 /ProportionalMetrics false /Kana false /Italics false /Ruby false /BaselineDirection 1 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /JapaneseAlternateFeature 0 /EnableWariChu false /WariChuLineCount 2 /WariChuLineGap 0 /WariChuSubLineAmount << /WariChuSubLineScale .5 >> /WariChuWidowAmount 2 /WariChuOrphanAmount 2 /WariChuJustification 7 /TCYUpDownAdjustment 0 /TCYLeftRightAdjustment 0 /LeftAki -1.0 /RightAki -1.0 /JiDori 0 /NoBreak false /FillColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 .54902 .00862 .00867 ] >> >> /StrokeColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 .74902 .74902 .74902 ] >> >> /Blend << /StreamTag /SimpleBlender >> /FillFlag true /StrokeFlag false /FillFirst false /FillOverPrint false /StrokeOverPrint false /LineCap 0 /LineJoin 0 /LineWidth .57884 /MiterLimit 2.31535 /LineDashOffset 0.0 /LineDashArray [ ] /Type1EncodingNames [ ] /Kashidas 0 /DirOverride 0 /DigitSet 0 /DiacVPos 4 /DiacXOffset 0.0 /DiacYOffset 0.0 /OverlapSwash false /JustificationAlternates false /StretchedAlternates false /FillVisibleFlag true /StrokeVisibleFlag true >> >> >> /Length 2 >> ] >> /KernRun << /RunArray [ << /RunData << >> /Length 2 >> ] >> /AlternateGlyphRun << /RunArray [ << /RunData << >> /Length 2 >> ] >> /FirstKern 0 >> /View << /Frames [ << /Resource 2 >> ] /RenderedData << /RunArray [ << /RunData << /LineCount 1 >> /Length 2 >> ] >> /Strikes [ << /StreamTag /PathSelectGroupCharacter /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 0 /Children [ << /StreamTag /FrameStrike /Frame 2 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 2 /Children [ << /StreamTag /RowColStrike /RowColIndex 0 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 1 /Children [ << /StreamTag /RowColStrike /RowColIndex 0 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 2 /Children [ << /StreamTag /LineStrike /Baseline 0.0 /Leading 240.00002 /EMHeight 200.0 /DHeight 150.09766 /SelectionAscent -200.88136 /SelectionDescent 57.35962 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 -200.88136 0.0 57.35962 ] /ChildProcession 1 /Children [ << /StreamTag /Segment /Mapping << /CharacterCount 2 /GlyphCount 0 /WRValid false >> /FirstCharacterIndexInSegment 0 /Transform << /Origin [ -149.39575 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 1 /Children [ << /StreamTag /GlyphStrike /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 -200.88136 149.39575 57.35962 ] /Glyphs [ 94 1 ] /GlyphAdjustments << /Data [ << >> ] /RunLengths [ 2 ] >> /VisualBounds [ -149.39575 -200.88136 0.0 57.35962 ] /RenderedBounds [ -149.39575 -200.88136 0.0 57.35962 ] /Invalidation [ -149.39575 -200.88136 149.39575 57.35962 ] /ShadowStylesRun << /Data [ << /Index 0 /Font 1 /Scale [ 1.0 1.2 ] /Orientation 0 /BaselineDirection 2 /BaselineShift 0.0 /KernType 0 /EmbeddingLevel 0 /ComplementaryFontIndex 0 >> << /Index 1 /Font 1 /Scale [ 1.0 1.2 ] /Orientation 0 /BaselineDirection 2 /BaselineShift 0.0 /KernType 0 /EmbeddingLevel 0 /ComplementaryFontIndex 0 >> ] /RunLengths [ 1 1 ] >> /EndsInCR true /SelectionAscent -200.88136 /SelectionDescent 57.35962 /MainDir 0 >> ] >> ] >> ] >> ] >> ] >> ] >> ] >> /OpticalAlignment false >> << /Model << /Text (YARA ) /ParagraphRun << /RunArray [ << /RunData << /ParagraphSheet << /Name () /Features << /Justification 1 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /DropCaps 1 /AutoLeading 1.2 /LeadingType 0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /HyphenateCapitalized true /HyphenationPreference .5 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /SingleWordJustification 6 /Hanging false /AutoTCY 1 /KeepTogether true /BurasagariType 0 /KinsokuOrder 0 /Kinsoku /nil /KurikaeshiMojiShori false /MojiKumiTable /nil /EveryLineComposer false /TabStops << >> /DefaultTabWidth 36.0 /DefaultStyle << /Font 3 /FontSize 12.0 /FauxBold false /FauxItalic false /AutoLeading true /Leading 0.0 /HorizontalScale 1.0 /VerticalScale 1.0 /Tracking 0 /BaselineShift 0.0 /CharacterRotation 0.0 /AutoKern 1 /FontCaps 0 /FontBaseline 0 /FontOTPosition 0 /StrikethroughPosition 0 /UnderlinePosition 0 /UnderlineOffset 0.0 /Ligatures true /DiscretionaryLigatures false /ContextualLigatures false /AlternateLigatures false /OldStyle false /Fractions false /Ordinals false /Swash false /Titling false /ConnectionForms false /StylisticAlternates false /Ornaments false /FigureStyle 0 /ProportionalMetrics false /Kana false /Italics false /Ruby false /BaselineDirection 2 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /JapaneseAlternateFeature 0 /EnableWariChu false /WariChuLineCount 2 /WariChuLineGap 0 /WariChuSubLineAmount << /WariChuSubLineScale .5 >> /WariChuWidowAmount 2 /WariChuOrphanAmount 2 /WariChuJustification 7 /TCYUpDownAdjustment 0 /TCYLeftRightAdjustment 0 /LeftAki -1.0 /RightAki -1.0 /JiDori 0 /NoBreak false /FillColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> >> /StrokeColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> >> /Blend << /StreamTag /SimpleBlender >> /FillFlag true /StrokeFlag false /FillFirst true /FillOverPrint false /StrokeOverPrint false /LineCap 0 /LineJoin 0 /LineWidth 1.0 /MiterLimit 4.0 /LineDashOffset 0.0 /LineDashArray [ ] /Type1EncodingNames [ ] /Kashidas 0 /DirOverride 0 /DigitSet 0 /DiacVPos 4 /DiacXOffset 0.0 /DiacYOffset 0.0 /OverlapSwash false /JustificationAlternates false /StretchedAlternates false /FillVisibleFlag true /StrokeVisibleFlag true >> /ParagraphDirection 0 /JustificationMethod 0 /ComposerEngine 0 >> /Parent 0 >> >> /Length 5 >> ] >> /StyleRun << /RunArray [ << /RunData << /StyleSheet << /Name () /Parent 0 /Features << /Font 0 /FontSize 41.66667 /FauxBold false /FauxItalic false /AutoLeading true /Leading .04167 /HorizontalScale 1.2 /VerticalScale .9 /Tracking 60 /BaselineShift 0.0 /CharacterRotation 0.0 /AutoKern 0 /FontCaps 0 /FontBaseline 0 /FontOTPosition 0 /StrikethroughPosition 0 /UnderlinePosition 0 /UnderlineOffset 0.0 /Ligatures true /DiscretionaryLigatures false /ContextualLigatures false /AlternateLigatures false /OldStyle false /Fractions false /Ordinals false /Swash false /Titling false /ConnectionForms false /StylisticAlternates false /Ornaments false /FigureStyle 0 /ProportionalMetrics false /Kana false /Italics false /Ruby false /BaselineDirection 1 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /JapaneseAlternateFeature 0 /EnableWariChu false /WariChuLineCount 2 /WariChuLineGap 0 /WariChuSubLineAmount << /WariChuSubLineScale .5 >> /WariChuWidowAmount 2 /WariChuOrphanAmount 2 /WariChuJustification 7 /TCYUpDownAdjustment 0 /TCYLeftRightAdjustment 0 /LeftAki -1.0 /RightAki -1.0 /JiDori 0 /NoBreak false /FillColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> >> /StrokeColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 .74902 .74902 .74902 ] >> >> /Blend << /StreamTag /SimpleBlender >> /FillFlag true /StrokeFlag false /FillFirst false /FillOverPrint false /StrokeOverPrint false /LineCap 0 /LineJoin 0 /LineWidth .57884 /MiterLimit 2.31535 /LineDashOffset 0.0 /LineDashArray [ ] /Type1EncodingNames [ ] /Kashidas 0 /DirOverride 0 /DigitSet 0 /DiacVPos 4 /DiacXOffset 0.0 /DiacYOffset 0.0 /OverlapSwash false /JustificationAlternates false /StretchedAlternates false /FillVisibleFlag true /StrokeVisibleFlag true >> >> >> /Length 5 >> ] >> /KernRun << /RunArray [ << /RunData << >> /Length 5 >> ] >> /AlternateGlyphRun << /RunArray [ << /RunData << >> /Length 5 >> ] >> >> /View << /Frames [ << /Resource 1 >> ] /RenderedData << /RunArray [ << /RunData << /LineCount 1 >> /Length 5 >> ] >> /Strikes [ << /StreamTag /PathSelectGroupCharacter /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 0 /Children [ << /StreamTag /FrameStrike /Frame 1 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 2 /Children [ << /StreamTag /RowColStrike /RowColIndex 0 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 1 /Children [ << /StreamTag /RowColStrike /RowColIndex 0 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 2 /Children [ << /StreamTag /LineStrike /Baseline 0.0 /Leading 50.0 /EMHeight 41.66667 /DHeight 31.25 /SelectionAscent -30.00011 /SelectionDescent 15.26356 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 -30.00011 0.0 15.26356 ] /ChildProcession 1 /Children [ << /StreamTag /Segment /Mapping << /CharacterCount 5 /GlyphCount 0 /WRValid false >> /FirstCharacterIndexInSegment 0 /Transform << /Origin [ -142.27942 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 1 /Children [ << /StreamTag /GlyphStrike /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 -30.00011 145.27942 15.26356 ] /Glyphs [ 174 150 167 150 3 ] /GlyphAdjustments << /Data [ << /BackFixed 3.0 >> ] /RunLengths [ 5 ] >> /VisualBounds [ -142.27942 -30.00011 3.0 15.26356 ] /RenderedBounds [ -142.27942 -30.00011 3.0 15.26356 ] /Invalidation [ -142.27942 -30.00011 26.99979 15.26356 ] /ShadowStylesRun << /Data [ << /Index 0 /Font 0 /Scale [ 1.2 .9 ] /Orientation 0 /BaselineDirection 2 /BaselineShift 0.0 /KernType 0 /EmbeddingLevel 0 /ComplementaryFontIndex 0 >> ] /RunLengths [ 5 ] >> /EndsInCR true /SelectionAscent -30.00011 /SelectionDescent 15.26356 /MainDir 0 >> ] >> ] >> ] >> ] >> ] >> ] >> ] >> /OpticalAlignment false >> << /Model << /Text (/* ) /ParagraphRun << /RunArray [ << /RunData << /ParagraphSheet << /Name () /Features << /Justification 1 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /DropCaps 1 /AutoLeading 1.2 /LeadingType 0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /HyphenateCapitalized true /HyphenationPreference .5 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /SingleWordJustification 6 /Hanging false /AutoTCY 1 /KeepTogether true /BurasagariType 0 /KinsokuOrder 0 /Kinsoku /nil /KurikaeshiMojiShori false /MojiKumiTable /nil /EveryLineComposer false /TabStops << >> /DefaultTabWidth 36.0 /DefaultStyle << /Font 0 /FontSize 12.0 /FauxBold false /FauxItalic false /AutoLeading true /Leading 0.0 /HorizontalScale 1.0 /VerticalScale 1.0 /Tracking 0 /BaselineShift 0.0 /CharacterRotation 0.0 /AutoKern 1 /FontCaps 0 /FontBaseline 0 /FontOTPosition 0 /StrikethroughPosition 0 /UnderlinePosition 0 /UnderlineOffset 0.0 /Ligatures true /DiscretionaryLigatures false /ContextualLigatures false /AlternateLigatures false /OldStyle false /Fractions false /Ordinals false /Swash false /Titling false /ConnectionForms false /StylisticAlternates false /Ornaments false /FigureStyle 0 /ProportionalMetrics false /Kana false /Italics false /Ruby false /BaselineDirection 2 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /EnableWariChu false /WariChuLineCount 2 /WariChuLineGap 0 /WariChuSubLineAmount << /WariChuSubLineScale .5 >> /WariChuWidowAmount 2 /WariChuOrphanAmount 2 /WariChuJustification 7 /TCYUpDownAdjustment 0 /TCYLeftRightAdjustment 0 /LeftAki -1.0 /RightAki -1.0 /JiDori 0 /NoBreak false /FillColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> >> /StrokeColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> >> /FillFlag true /StrokeFlag false /FillFirst true /FillOverPrint false /StrokeOverPrint false /LineCap 0 /LineJoin 0 /LineWidth 1.0 /MiterLimit 4.0 /LineDashOffset 0.0 /LineDashArray [ ] /Type1EncodingNames [ ] /Kashidas 0 /DirOverride 0 /DigitSet 0 /DiacVPos 4 /DiacXOffset 0.0 /DiacYOffset 0.0 /OverlapSwash false /JustificationAlternates false /StretchedAlternates false /FillVisibleFlag true /StrokeVisibleFlag true >> /ParagraphDirection 0 /JustificationMethod 0 /ComposerEngine 0 >> /Parent 0 >> >> /Length 3 >> ] >> /StyleRun << /RunArray [ << /RunData << /StyleSheet << /Name () /Parent 0 /Features << /Font 0 /FontSize 41.66667 /FauxBold false /FauxItalic false /AutoLeading true /Leading 50.0 /HorizontalScale 1.0 /VerticalScale .9 /Tracking -150 /BaselineShift 0.0 /CharacterRotation 0.0 /AutoKern 0 /FontCaps 0 /FontBaseline 0 /FontOTPosition 0 /StrikethroughPosition 0 /UnderlinePosition 0 /UnderlineOffset 0.0 /Ligatures true /DiscretionaryLigatures false /ContextualLigatures false /AlternateLigatures false /OldStyle false /Fractions false /Ordinals false /Swash false /Titling false /ConnectionForms false /StylisticAlternates false /Ornaments false /FigureStyle 0 /ProportionalMetrics false /Kana false /Italics false /Ruby false /BaselineDirection 1 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /JapaneseAlternateFeature 0 /EnableWariChu false /WariChuLineCount 2 /WariChuLineGap 0 /WariChuSubLineAmount << /WariChuSubLineScale .5 >> /WariChuWidowAmount 2 /WariChuOrphanAmount 2 /WariChuJustification 7 /TCYUpDownAdjustment 0 /TCYLeftRightAdjustment 0 /LeftAki -1.0 /RightAki -1.0 /JiDori 0 /NoBreak false /FillColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> >> /StrokeColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 .74902 .74902 .74902 ] >> >> /Blend << /StreamTag /SimpleBlender >> /FillFlag true /StrokeFlag false /FillFirst false /FillOverPrint false /StrokeOverPrint false /LineCap 0 /LineJoin 0 /LineWidth .57884 /MiterLimit 2.31535 /LineDashOffset 0.0 /LineDashArray [ ] /Type1EncodingNames [ ] /Kashidas 0 /DirOverride 0 /DigitSet 0 /DiacVPos 4 /DiacXOffset 0.0 /DiacYOffset 0.0 /OverlapSwash false /JustificationAlternates false /StretchedAlternates false /FillVisibleFlag true /StrokeVisibleFlag true >> >> >> /Length 3 >> ] >> /KernRun << /RunArray [ << /RunData << >> /Length 3 >> ] >> /AlternateGlyphRun << /RunArray [ << /RunData << >> /Length 3 >> ] >> /FirstKern 0 >> /View << /Frames [ << /Resource 3 >> ] /RenderedData << /RunArray [ << /RunData << /LineCount 1 >> /Length 3 >> ] >> /Strikes [ << /StreamTag /PathSelectGroupCharacter /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 0 /Children [ << /StreamTag /FrameStrike /Frame 3 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 2 /Children [ << /StreamTag /RowColStrike /RowColIndex 0 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 1 /Children [ << /StreamTag /RowColStrike /RowColIndex 0 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 2 /Children [ << /StreamTag /LineStrike /Baseline 0.0 /Leading 50.0 /EMHeight 41.66667 /DHeight 31.25 /SelectionAscent -30.00011 /SelectionDescent 15.26356 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 -30.00011 0.0 15.26356 ] /ChildProcession 1 /Children [ << /StreamTag /Segment /Mapping << /CharacterCount 3 /GlyphCount 0 /WRValid false >> /FirstCharacterIndexInSegment 0 /Transform << /Origin [ -42.38229 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 1 /Children [ << /StreamTag /GlyphStrike /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 -30.00011 36.13229 15.26356 ] /Glyphs [ 132 127 3 ] /GlyphAdjustments << /Data [ << /BackFixed -6.25 >> ] /RunLengths [ 3 ] >> /VisualBounds [ -42.38229 -31.27499 -3.29654 15.26356 ] /RenderedBounds [ -42.38229 -31.27499 -3.29654 15.26356 ] /Invalidation [ -42.38229 -31.27499 13.74982 15.26356 ] /ShadowStylesRun << /Data [ << /Index 0 /Font 0 /Scale [ 1.0 .9 ] /Orientation 0 /BaselineDirection 2 /BaselineShift 0.0 /KernType 0 /EmbeddingLevel 0 /ComplementaryFontIndex 0 >> << /Index 1 /Font 0 /Scale [ 1.0 .9 ] /Orientation 0 /BaselineDirection 2 /BaselineShift 0.0 /KernType 0 /EmbeddingLevel 0 /ComplementaryFontIndex 0 >> ] /RunLengths [ 1 2 ] >> /EndsInCR true /SelectionAscent -30.00011 /SelectionDescent 15.26356 /MainDir 0 >> ] >> ] >> ] >> ] >> ] >> ] >> ] >> /OpticalAlignment false >> << /Model << /Text (*/ ) /ParagraphRun << /RunArray [ << /RunData << /ParagraphSheet << /Name () /Features << /Justification 1 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /DropCaps 1 /AutoLeading 1.2 /LeadingType 0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /HyphenateCapitalized true /HyphenationPreference .5 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /SingleWordJustification 6 /Hanging false /AutoTCY 1 /KeepTogether true /BurasagariType 0 /KinsokuOrder 0 /Kinsoku /nil /KurikaeshiMojiShori false /MojiKumiTable /nil /EveryLineComposer false /TabStops << >> /DefaultTabWidth 36.0 /DefaultStyle << /Font 0 /FontSize 12.0 /FauxBold false /FauxItalic false /AutoLeading true /Leading 0.0 /HorizontalScale 1.0 /VerticalScale 1.0 /Tracking 0 /BaselineShift 0.0 /CharacterRotation 0.0 /AutoKern 1 /FontCaps 0 /FontBaseline 0 /FontOTPosition 0 /StrikethroughPosition 0 /UnderlinePosition 0 /UnderlineOffset 0.0 /Ligatures true /DiscretionaryLigatures false /ContextualLigatures false /AlternateLigatures false /OldStyle false /Fractions false /Ordinals false /Swash false /Titling false /ConnectionForms false /StylisticAlternates false /Ornaments false /FigureStyle 0 /ProportionalMetrics false /Kana false /Italics false /Ruby false /BaselineDirection 2 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /EnableWariChu false /WariChuLineCount 2 /WariChuLineGap 0 /WariChuSubLineAmount << /WariChuSubLineScale .5 >> /WariChuWidowAmount 2 /WariChuOrphanAmount 2 /WariChuJustification 7 /TCYUpDownAdjustment 0 /TCYLeftRightAdjustment 0 /LeftAki -1.0 /RightAki -1.0 /JiDori 0 /NoBreak false /FillColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> >> /StrokeColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> >> /FillFlag true /StrokeFlag false /FillFirst true /FillOverPrint false /StrokeOverPrint false /LineCap 0 /LineJoin 0 /LineWidth 1.0 /MiterLimit 4.0 /LineDashOffset 0.0 /LineDashArray [ ] /Type1EncodingNames [ ] /Kashidas 0 /DirOverride 0 /DigitSet 0 /DiacVPos 4 /DiacXOffset 0.0 /DiacYOffset 0.0 /OverlapSwash false /JustificationAlternates false /StretchedAlternates false /FillVisibleFlag true /StrokeVisibleFlag true >> /ParagraphDirection 0 /JustificationMethod 0 /ComposerEngine 0 >> /Parent 0 >> >> /Length 3 >> ] >> /StyleRun << /RunArray [ << /RunData << /StyleSheet << /Name () /Parent 0 /Features << /Font 0 /FontSize 41.66667 /FauxBold false /FauxItalic false /AutoLeading true /Leading 50.0 /HorizontalScale 1.2 /VerticalScale .9 /Tracking -150 /BaselineShift 0.0 /CharacterRotation 0.0 /AutoKern 0 /FontCaps 0 /FontBaseline 0 /FontOTPosition 0 /StrikethroughPosition 0 /UnderlinePosition 0 /UnderlineOffset 0.0 /Ligatures true /DiscretionaryLigatures false /ContextualLigatures false /AlternateLigatures false /OldStyle false /Fractions false /Ordinals false /Swash false /Titling false /ConnectionForms false /StylisticAlternates false /Ornaments false /FigureStyle 0 /ProportionalMetrics false /Kana false /Italics false /Ruby false /BaselineDirection 1 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /JapaneseAlternateFeature 0 /EnableWariChu false /WariChuLineCount 2 /WariChuLineGap 0 /WariChuSubLineAmount << /WariChuSubLineScale .5 >> /WariChuWidowAmount 2 /WariChuOrphanAmount 2 /WariChuJustification 7 /TCYUpDownAdjustment 0 /TCYLeftRightAdjustment 0 /LeftAki -1.0 /RightAki -1.0 /JiDori 0 /NoBreak false /FillColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> >> /StrokeColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 .74902 .74902 .74902 ] >> >> /Blend << /StreamTag /SimpleBlender >> /FillFlag true /StrokeFlag false /FillFirst false /FillOverPrint false /StrokeOverPrint false /LineCap 0 /LineJoin 0 /LineWidth .57884 /MiterLimit 2.31535 /LineDashOffset 0.0 /LineDashArray [ ] /Type1EncodingNames [ ] /Kashidas 0 /DirOverride 0 /DigitSet 0 /DiacVPos 4 /DiacXOffset 0.0 /DiacYOffset 0.0 /OverlapSwash false /JustificationAlternates false /StretchedAlternates false /FillVisibleFlag true /StrokeVisibleFlag true >> >> >> /Length 3 >> ] >> /KernRun << /RunArray [ << /RunData << >> /Length 3 >> ] >> /AlternateGlyphRun << /RunArray [ << /RunData << >> /Length 3 >> ] >> /FirstKern 0 >> /View << /Frames [ << /Resource 4 >> ] /RenderedData << /RunArray [ << /RunData << /LineCount 1 >> /Length 3 >> ] >> /Strikes [ << /StreamTag /PathSelectGroupCharacter /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 0 /Children [ << /StreamTag /FrameStrike /Frame 4 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 2 /Children [ << /StreamTag /RowColStrike /RowColIndex 0 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 1 /Children [ << /StreamTag /RowColStrike /RowColIndex 0 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 2 /Children [ << /StreamTag /LineStrike /Baseline 0.0 /Leading 50.0 /EMHeight 41.66667 /DHeight 31.25 /SelectionAscent -30.00011 /SelectionDescent 15.26356 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 -30.00011 0.0 15.26356 ] /ChildProcession 1 /Children [ << /StreamTag /Segment /Mapping << /CharacterCount 3 /GlyphCount 0 /WRValid false >> /FirstCharacterIndexInSegment 0 /Transform << /Origin [ -50.85876 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 1 /Children [ << /StreamTag /GlyphStrike /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 -30.00011 43.35876 15.26356 ] /Glyphs [ 127 132 3 ] /GlyphAdjustments << /Data [ << /BackFixed -7.5 >> ] /RunLengths [ 3 ] >> /VisualBounds [ -50.85876 -31.27499 -4.17938 15.26356 ] /RenderedBounds [ -50.85876 -31.27499 -4.17938 15.26356 ] /Invalidation [ -50.85876 -31.27499 16.49979 15.26356 ] /ShadowStylesRun << /Data [ << /Index 0 /Font 0 /Scale [ 1.2 .9 ] /Orientation 0 /BaselineDirection 2 /BaselineShift 0.0 /KernType 0 /EmbeddingLevel 0 /ComplementaryFontIndex 0 >> << /Index 1 /Font 0 /Scale [ 1.2 .9 ] /Orientation 0 /BaselineDirection 2 /BaselineShift 0.0 /KernType 0 /EmbeddingLevel 0 /ComplementaryFontIndex 0 >> ] /RunLengths [ 1 2 ] >> /EndsInCR true /SelectionAscent -30.00011 /SelectionDescent 15.26356 /MainDir 0 >> ] >> ] >> ] >> ] >> ] >> ] >> ] >> /OpticalAlignment false >> << /Model << /Text ({ ) /ParagraphRun << /RunArray [ << /RunData << /ParagraphSheet << /Name () /Features << /Justification 1 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /DropCaps 1 /AutoLeading 1.2 /LeadingType 0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 8 /Zone 36.0 /HyphenateCapitalized true /HyphenationPreference .5 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /SingleWordJustification 6 /Hanging false /AutoTCY 1 /KeepTogether true /BurasagariType 0 /KinsokuOrder 0 /Kinsoku /nil /KurikaeshiMojiShori false /MojiKumiTable /nil /EveryLineComposer false /TabStops << >> /DefaultTabWidth 36.0 /DefaultStyle << /Font 0 /FontSize 12.0 /FauxBold false /FauxItalic false /AutoLeading true /Leading 0.0 /HorizontalScale 1.0 /VerticalScale 1.0 /Tracking 0 /BaselineShift 0.0 /CharacterRotation 0.0 /AutoKern 1 /FontCaps 0 /FontBaseline 0 /FontOTPosition 0 /StrikethroughPosition 0 /UnderlinePosition 0 /UnderlineOffset 0.0 /Ligatures true /DiscretionaryLigatures false /ContextualLigatures false /AlternateLigatures false /OldStyle false /Fractions false /Ordinals false /Swash false /Titling false /ConnectionForms false /StylisticAlternates false /Ornaments false /FigureStyle 0 /ProportionalMetrics false /Kana false /Italics false /Ruby false /BaselineDirection 2 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /EnableWariChu false /WariChuLineCount 2 /WariChuLineGap 0 /WariChuSubLineAmount << /WariChuSubLineScale .5 >> /WariChuWidowAmount 2 /WariChuOrphanAmount 2 /WariChuJustification 7 /TCYUpDownAdjustment 0 /TCYLeftRightAdjustment 0 /LeftAki -1.0 /RightAki -1.0 /JiDori 0 /NoBreak false /FillColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> >> /StrokeColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> >> /FillFlag true /StrokeFlag false /FillFirst true /FillOverPrint false /StrokeOverPrint false /LineCap 0 /LineJoin 0 /LineWidth 1.0 /MiterLimit 4.0 /LineDashOffset 0.0 /LineDashArray [ ] /Type1EncodingNames [ ] /Kashidas 0 /DirOverride 0 /DigitSet 0 /DiacVPos 4 /DiacXOffset 0.0 /DiacYOffset 0.0 /OverlapSwash false /JustificationAlternates false /StretchedAlternates false /FillVisibleFlag true /StrokeVisibleFlag true >> /ParagraphDirection 0 /JustificationMethod 0 /ComposerEngine 0 >> /Parent 0 >> >> /Length 2 >> ] >> /StyleRun << /RunArray [ << /RunData << /StyleSheet << /Name () /Parent 0 /Features << /Font 2 /FontSize 200.0 /FauxBold true /FauxItalic false /AutoLeading true /Leading 150.0 /HorizontalScale 1.0 /VerticalScale 1.2 /Tracking 0 /BaselineShift 0.0 /CharacterRotation 0.0 /AutoKern 0 /FontCaps 0 /FontBaseline 0 /FontOTPosition 0 /StrikethroughPosition 0 /UnderlinePosition 0 /UnderlineOffset 0.0 /Ligatures true /DiscretionaryLigatures false /ContextualLigatures false /AlternateLigatures false /OldStyle false /Fractions false /Ordinals false /Swash false /Titling false /ConnectionForms false /StylisticAlternates false /Ornaments false /FigureStyle 0 /ProportionalMetrics false /Kana false /Italics false /Ruby false /BaselineDirection 1 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /JapaneseAlternateFeature 0 /EnableWariChu false /WariChuLineCount 2 /WariChuLineGap 0 /WariChuSubLineAmount << /WariChuSubLineScale .5 >> /WariChuWidowAmount 2 /WariChuOrphanAmount 2 /WariChuJustification 7 /TCYUpDownAdjustment 0 /TCYLeftRightAdjustment 0 /LeftAki -1.0 /RightAki -1.0 /JiDori 0 /NoBreak false /FillColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 .54902 .00862 .00867 ] >> >> /StrokeColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 .74902 .74902 .74902 ] >> >> /Blend << /StreamTag /SimpleBlender >> /FillFlag true /StrokeFlag false /FillFirst false /FillOverPrint false /StrokeOverPrint false /LineCap 0 /LineJoin 0 /LineWidth .57884 /MiterLimit 2.31535 /LineDashOffset 0.0 /LineDashArray [ ] /Type1EncodingNames [ ] /Kashidas 0 /DirOverride 0 /DigitSet 0 /DiacVPos 4 /DiacXOffset 0.0 /DiacYOffset 0.0 /OverlapSwash false /JustificationAlternates false /StretchedAlternates false /FillVisibleFlag true /StrokeVisibleFlag true >> >> >> /Length 2 >> ] >> /KernRun << /RunArray [ << /RunData << >> /Length 2 >> ] >> /AlternateGlyphRun << /RunArray [ << /RunData << >> /Length 2 >> ] >> /FirstKern 0 >> /View << /Frames [ << /Resource 0 >> ] /RenderedData << /RunArray [ << /RunData << /LineCount 1 >> /Length 2 >> ] >> /Strikes [ << /StreamTag /PathSelectGroupCharacter /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 0 /Children [ << /StreamTag /FrameStrike /Frame 0 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 2 /Children [ << /StreamTag /RowColStrike /RowColIndex 0 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 1 /Children [ << /StreamTag /RowColStrike /RowColIndex 0 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 2 /Children [ << /StreamTag /LineStrike /Baseline 0.0 /Leading 240.00002 /EMHeight 200.0 /DHeight 150.09766 /SelectionAscent -200.88136 /SelectionDescent 57.35962 /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 -200.88136 0.0 57.35962 ] /ChildProcession 1 /Children [ << /StreamTag /Segment /Mapping << /CharacterCount 2 /GlyphCount 0 /WRValid false >> /FirstCharacterIndexInSegment 0 /Transform << /Origin [ -149.39575 0.0 ] >> /Bounds [ 0.0 0.0 0.0 0.0 ] /ChildProcession 1 /Children [ << /StreamTag /GlyphStrike /Transform << /Origin [ 0.0 0.0 ] >> /Bounds [ 0.0 -200.88136 149.39575 57.35962 ] /Glyphs [ 92 1 ] /GlyphAdjustments << /Data [ << >> ] /RunLengths [ 2 ] >> /VisualBounds [ -149.39575 -200.88136 0.0 57.35962 ] /RenderedBounds [ -149.39575 -200.88136 0.0 57.35962 ] /Invalidation [ -149.39575 -200.88136 149.39575 57.35962 ] /ShadowStylesRun << /Data [ << /Index 0 /Font 1 /Scale [ 1.0 1.2 ] /Orientation 0 /BaselineDirection 2 /BaselineShift 0.0 /KernType 0 /EmbeddingLevel 0 /ComplementaryFontIndex 0 >> << /Index 1 /Font 1 /Scale [ 1.0 1.2 ] /Orientation 0 /BaselineDirection 2 /BaselineShift 0.0 /KernType 0 /EmbeddingLevel 0 /ComplementaryFontIndex 0 >> ] /RunLengths [ 1 1 ] >> /EndsInCR true /SelectionAscent -200.88136 /SelectionDescent 57.35962 /MainDir 0 >> ] >> ] >> ] >> ] >> ] >> ] >> ] >> /OpticalAlignment false >> ] /OriginalNormalStyleFeatures << /Font 3 /FontSize 12.0 /FauxBold false /FauxItalic false /AutoLeading true /Leading 0.0 /HorizontalScale 1.0 /VerticalScale 1.0 /Tracking 0 /BaselineShift 0.0 /CharacterRotation 0.0 /AutoKern 1 /FontCaps 0 /FontBaseline 0 /FontOTPosition 0 /StrikethroughPosition 0 /UnderlinePosition 0 /UnderlineOffset 0.0 /Ligatures true /DiscretionaryLigatures false /ContextualLigatures false /AlternateLigatures false /OldStyle false /Fractions false /Ordinals false /Swash false /Titling false /ConnectionForms false /StylisticAlternates false /Ornaments false /FigureStyle 0 /ProportionalMetrics false /Kana false /Italics false /Ruby false /BaselineDirection 2 /Tsume 0.0 /StyleRunAlignment 2 /Language 0 /JapaneseAlternateFeature 0 /EnableWariChu false /WariChuLineCount 2 /WariChuLineGap 0 /WariChuSubLineAmount << /WariChuSubLineScale .5 >> /WariChuWidowAmount 2 /WariChuOrphanAmount 2 /WariChuJustification 7 /TCYUpDownAdjustment 0 /TCYLeftRightAdjustment 0 /LeftAki -1.0 /RightAki -1.0 /JiDori 0 /NoBreak false /FillColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> >> /StrokeColor << /StreamTag /SimplePaint /Color << /Type 1 /Values [ 1.0 0.0 0.0 0.0 ] >> >> /Blend << /StreamTag /SimpleBlender >> /FillFlag true /StrokeFlag false /FillFirst true /FillOverPrint false /StrokeOverPrint false /LineCap 0 /LineJoin 0 /LineWidth 1.0 /MiterLimit 4.0 /LineDashOffset 0.0 /LineDashArray [ ] /Type1EncodingNames [ ] /Kashidas 0 /DirOverride 0 /DigitSet 0 /DiacVPos 4 /DiacXOffset 0.0 /DiacYOffset 0.0 /OverlapSwash false /JustificationAlternates false /StretchedAlternates false /FillVisibleFlag true /StrokeVisibleFlag true >> /OriginalNormalParagraphFeatures << /Justification 0 /FirstLineIndent 0.0 /StartIndent 0.0 /EndIndent 0.0 /SpaceBefore 0.0 /SpaceAfter 0.0 /DropCaps 1 /AutoLeading 1.2 /LeadingType 0 /AutoHyphenate true /HyphenatedWordSize 6 /PreHyphen 2 /PostHyphen 2 /ConsecutiveHyphens 0 /Zone 36.0 /HyphenateCapitalized true /HyphenationPreference .5 /WordSpacing [ .8 1.0 1.33 ] /LetterSpacing [ 0.0 0.0 0.0 ] /GlyphSpacing [ 1.0 1.0 1.0 ] /SingleWordJustification 6 /Hanging false /AutoTCY 0 /KeepTogether true /BurasagariType 0 /KinsokuOrder 0 /Kinsoku /nil /KurikaeshiMojiShori false /MojiKumiTable /nil /EveryLineComposer false /TabStops << >> /DefaultTabWidth 36.0 /DefaultStyle << >> /ParagraphDirection 0 /JustificationMethod 0 /ComposerEngine 0 >> >>8BIMFMsk 2????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????x?c##?T?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?T?q????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????jZZ???"22? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij?c##????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##?)ij? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????x?0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????jZZ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????T?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?q???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????[? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????jZZ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?x????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????x?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????[? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????x?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????x?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????M}~? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????q? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????M}~? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?M}~????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????7? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?jZZ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????)ij? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?T????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"22?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????q? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??jZZ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??jZZ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij?q???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??7?c##?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????x?[?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?M}~?c##?x???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????q?7? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??7?c##????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????T? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??T??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij?jZZ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????[? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??T???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????x?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?T??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????M}~? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?T?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????"22? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?T????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????q? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??jZZ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????[? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"22?x??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?jZZ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????)ij? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?c##????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?x???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????M}~? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?T???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"22???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????7? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?jZZ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????7? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?c##??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????x?"22? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?c##??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????jZZ?"22? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?M}~??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????x?7? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????q???"22? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????[? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????7? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?c##??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????)ij? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?c##??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?c##??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????jZZ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?q??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????x?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????7? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij???????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????7? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##?)ij? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?T???????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????jZZ?c##?c##?M}~?7?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?q???????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????q???"22? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????x?7? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????jZZ?"22? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????x?"22? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????7? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?q?????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????7? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0??????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?c##??????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7???????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????M}~? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??q???????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?M}~????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij?????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????)ij? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??x?????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?c##?????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??x????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????[? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?jZZ???????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????q? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij???????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????"22? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?c##??????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????M}~? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0??????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????x?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?q?????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????[? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??????????????????????????????????????????????????????????????????????????????????jZZ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"22???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????T? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?jZZ????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????q?7? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?jZZ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????x?[?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?0?)ij?)ij?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"22????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?M}~??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????q?T?)ij? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?x????????????????????????????????????????????????????????????????????????????????)ij? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"22?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[????????????????????????????????????????????????????????????????????????????????0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?c##?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????x?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"22??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij????????????????????????????????????????????????????????????????????????????????[? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7?x?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????)ij? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?????????????????????????????????????????????????????????????????????????????????q? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??T????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????T? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??0?FFF?c##?c##?c##??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????x? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?q????????????????????????????????????????????????????????????????????????????????0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??7?c##?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?c##????????????????????????????????????????????????????????????????????????????????T? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij?q???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????)ij? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?c##????????????????????????????????????????????????????????????????????????????????x? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??jZZ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[?????????????????????????????????????????????????????????????????????????????????0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??jZZ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????T? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"22?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????M}~? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?T????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????x?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?jZZ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????M}~? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?M}~???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????????"22? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????)ij? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????????q?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????????)ij? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????????T? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????x?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????x?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?x???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?q????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????T? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????x? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????T? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij?c##????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????7? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij?)ij?)ij?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?FFF?T?q??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??M}~?jZZ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????q? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??M}~??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????[? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?jZZ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??x????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????)ij? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?x?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?7?T?x?????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??FFF????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"22?x??????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????jZZ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"22?x?????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0?????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?c##????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????"22? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?q???????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?T???????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????jZZ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij???????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij???????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????q? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij???????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????7? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij???????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????q? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij???????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij???????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????"22? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????jZZ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?T???????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????T? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?q???????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????7? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?c##????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????T? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0?????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"22?x?????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????x?FFF?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?"22?x??????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????x?M}~?"22? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??FFF????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????x?[?FFF?7?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?7?T?x?????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????c##? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????[???)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?"22? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????T?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????x?7? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?FFF??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?c##?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?c##????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????q?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?c##?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????jZZ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?0????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????T? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?M}~????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?q????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????)ij? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?T?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????)ij? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)ij???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????T? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??q???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????jZZ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?[?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????q?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????FFF? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??T????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????x?7? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?7?x???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????T?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??FFF?q???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????[???)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?)ij?0?FFF?[?q???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p?@?@?@?p?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`?@?@?@?P???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????=?p????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>? ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>???????????????????????????????????@?@?@?@?@?@?@?@?p????????`?@?@?@?@?@?@?@?P??????????????????p?@?@?@?@?@?@?@?@?@?@?@?`??????????????????`?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?P?????????????????????????`?@?@?@?@?@?@?@?@?@?@?@?p???????????????????????????????????????????????????????0>@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ?`???????????????????????????????????@????????>???????????????p?>@>>?`???????????????=>?@???????????????????`>>>@??p???????????????????????????????????????????????????>?@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>????????????????????????????????????@????????>??????????????@=???????????????>?p????????????????=?@?????????????????????????????????????????????????? >???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@?@?????????>>???????????????????????@????????>????????????? >?????????????>@??????????????>? ?????????????????????@???????????????????????p>?@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>??????????>>???????????????????????@????????>????????????`=>?@?@?@?=?0????????????>??????0>??????????????0=??@?@?@>=?`????????????????????@???????????????????????>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`? ?????p?????>>??????p?????????????????@????????>?????????????P??????p>>????????????>???????>=????????????>>?p??????P???????????????p??????@???????p???????????????p=?`??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>?????>>? ???>>???? >>?????????????????@????????>???????????>>???????? ????????????>????????p?@???????????? ???????>>?????????????0>?@????@????? >@=?`??????????????>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p=??????@>? ?>>?? >?@????????????????@????????>???????????>?????????@????????????>?????????@????????????@????????>????????????P=>? ?p?@??`?=>@?p????????????`=?`???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????=?p?????>>>>?????????????????@????????>???????????>?????????@????????????>?????????@????????????@????????>????????????==>>>?@???????????>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>???????`>>?`?????????????????@????????>???????????>?????????@????????????>?????????@????????????@????????>?????????????p?>>? ?????????????`=?p??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ?`?????????@>>?@???????????????????@????????>???????????>?????????@????????????>????????=?????????????@????????>????????????????0>>?P??????????????>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>???????????@>>?@???????????????????>>???????p>>???????????>?????????@????????????>????????0??????????????@????????>?????????????????@>>?`???????????????@=?p???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@?@?????????@>>?@??????????????????>?`????@>@?@???????????>?????????@????????????>???????@=>??????????????@????????>??????????????? >@>?@????????????>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>????????`>>?`????????????????p>>@>>>????????????>>???????>????????????>?????>@>??????????????>???????>>????????????`?=>? ?p?????????@>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`? ???????>>? >>? >>?????????????????`>@>?p????????????>????????????=>?@???????????????>????????????>??0?`>=?P????????>? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>?????????p>>? ??>>??? >>?p??????????????????? >=>?@??????????????>????????????=>?p????????????>????????????>>? ???@???p?>?????????? >????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p=???????????0? ????>>????? ?0???????????????????????@?0>>?@?P?????????????????>>???????>????????????>?????>@>????????????>???????>>?????????????p>?P?????@??????0??????????>?@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????=?p???????????????>>??????????????????????????????>????????????????????>?????????@????????????>???????@=?P????????????@????????>????????????????????@???????????????? >????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>????????????????>>??????????????????????????????>????????????????????>?????????@????????????>????????@?@????????????@????????>????????????????????@???????????????p>?@???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ?`????????????????? ??? ??????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>????????????????????`???????????????????>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>???????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>??????????????????????????????????????p=?`????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@?@???????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>??????????????????????????????????????>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>@????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>?????????????????????????????????????`=?`????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`? ????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>????????????????????????????????????>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>?????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>????????????????????????????????????`=?p????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p=??????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>???????????????????????????????????>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????=?p?????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>???????????????????????????????????@=?p????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>??????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>??????????????????????????????????>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ?`??????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>??????????????????????????????????@>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>@>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#P?@@? ?????????????????????????????????? ?`F????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Pi>{>G,H< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O?@@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@>O< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>{?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#P>< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>B???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Pi=< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? =< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?`F???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>B??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Pi=< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?p#P????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#P>< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?0???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#P=< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#P=< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????1< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`F< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>B????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????1< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?1???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>B< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?Pi???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>O< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>G,H?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`F< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @=?Pi?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @=?Pi??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O?`F???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>>B?@@?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????p ?0???????????????????????????????????@?p ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?????????????????????????????????????????????`@@>‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>‚?@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>? ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>?P``????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @??????????????????????????????????????????0<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?????????????????????????????????????????p ><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<? ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<? ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????>F<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????`@@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=?P``???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????0<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>F?p ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>BB??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?P``?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????>BB<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>‚????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?p ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>‚???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>F???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????>‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?P``??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?????????????????????????????????????????>‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @??????????????????????????????????????????p >F<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????P``>F<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????????p >‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @??????????????????????????????????????????????`@@>BB>F<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>B< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?@@??????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>O< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?@@??????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?@@??????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Pi< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?`F??????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>{< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#P=< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>B< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>B< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@>O< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @? ???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Pi?@@?@@?1>B>< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?`F???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`F>{>G,H< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#P>B< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>B????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Pi>G,H< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?0????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#P>G,H< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @=?????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>B< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>{?????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?`F?????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>B< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>??????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????=< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?@@??????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>B???????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????1< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @=?`F???????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?1????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>{< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O?????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>O< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @=?p#P?????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?@@?????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>?p#P????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>{????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?Pi???????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`F< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O???????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>G,H< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?@@??????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????1< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>??????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#P>< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?`F?????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>{?????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>?????????????????????????????????????????????????????????????????????????????????P``<<<<<<<<<<<<<<<<<<<<<>F??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? < @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?Pi????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`F>B< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>{????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<?P``?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#P?0???????????????????>>O>O=< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>G,H????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`F? >O< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?p#P???????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<>F?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@=< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?0???????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<?@?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#P=< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<>F??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O????????????????????????????????????????????????????????????????????????????????0<<<<<<<<<<<<<<<<<<<<<<<>‚?p ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>O< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>????????????????????????????????????????????????????????????????????????????????`@@<<<<<<<<<<<<<<<<<<<<<<<<>? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? < @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????????????????????????????????????????????=<<<<<<<<<<<<<<<<<<<<<<<<<=>??@?@?@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#P< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?`F???????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>‚?@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?@@???????????????????????????????????????????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>?`@@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>O< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?@@????????????????????????????????????????????????????????????????????????????????p <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=?P``??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?0????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=?P``?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?????????????????????????????????????????????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>F?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????1< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @??????????????????????????????????????????????????????????????????????????????????=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????????p =<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?P``???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????????????????????????????????????????????????>F<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>‚???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @??????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @??????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @??????????????????????????????????????????????????????????????????????????????????????`@@=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????????????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????????????????????????????????????????????????p =<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?0???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????????p =<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?p ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>‚????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @??????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?`@@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?????????????????????????????????????????????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>‚??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?????????????????????????????????????????????????????????????????????????????????p <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>BB???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>?@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????????????????????????????????????????????>‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>???????????????????? ?`@@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<>??P``???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????????????????????????????????????????????`@@<<<<<<<<<<<<<<<<<<<<<<<=???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????????????????????????????????????????????0<<<<<<<<<<<<<<<<<<<<<<<?P``???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<=?p ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<>BB?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????=<<<<<<<<<<<<<<<<<<<<<?0?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<?p ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<=??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<>BB??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>B? ?p#P?????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @=?????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>G,H?p#P??????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Pi< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>G,H?p#P?????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>?????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?@@????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>G,H< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?`F???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @? ???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Pi< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>{???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????=< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>{< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`F< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>B< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`F< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>G,H< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>{???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Pi=< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @? ???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? < @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?`F???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>O????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>B< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @?@@????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? < @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>?????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@@>< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>G,H?p#P?????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#P?=< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @>G,H?p#P??????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#P?1>G,H< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @< @=?????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#P?0?>B>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>O>B? ?p#P?????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0>BB>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>F<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p >‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?@?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`@@=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?@???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>BB<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????P``<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?`@@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?0??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=?`@@???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????P``<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?0????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>BB?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>BB<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>‚???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`@@=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>‚?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>‚??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p >‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>‚?p ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>??`@@???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0>BB>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??0?`@@???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p?@?@?@?p?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`?@?@?@?P???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????=?p????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>? ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>???????????????????????????????????@?@?@?@?@?@?@?@?p????????`?@?@?@?@?@?@?@?P??????????????????p?@?@?@?@?@?@?@?@?@?@?@?`??????????????????`?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?P?????????????????????????`?@?@?@?@?@?@?@?@?@?@?@?p???????????????????????????????????????????????????????0>@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ?`???????????????????????????????????@????????>???????????????p?>@>>?`???????????????=>?@???????????????????`>>>@??p???????????????????????????????????????????????????>?@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>????????????????????????????????????@????????>??????????????@=???????????????>?p????????????????=?@?????????????????????????????????????????????????? >???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@?@?????????>>???????????????????????@????????>????????????? >?????????????>@??????????????>? ?????????????????????@???????????????????????p>?@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>??????????>>???????????????????????@????????>????????????`=>?@?@?@?=?0????????????>??????0>??????????????0=??@?@?@>=?`????????????????????@???????????????????????>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`? ?????p?????>>??????p?????????????????@????????>?????????????P??????p>>????????????>???????>=????????????>>?p??????P???????????????p??????@???????p???????????????p=?`??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>?????>>? ???>>???? >>?????????????????@????????>???????????>>???????? ????????????>????????p?@???????????? ???????>>?????????????0>?@????@????? >@=?`??????????????>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p=??????@>? ?>>?? >?@????????????????@????????>???????????>?????????@????????????>?????????@????????????@????????>????????????P=>? ?p?@??`?=>@?p????????????`=?`???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????=?p?????>>>>?????????????????@????????>???????????>?????????@????????????>?????????@????????????@????????>????????????==>>>?@???????????>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>???????`>>?`?????????????????@????????>???????????>?????????@????????????>?????????@????????????@????????>?????????????p?>>? ?????????????`=?p??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ?`?????????@>>?@???????????????????@????????>???????????>?????????@????????????>????????=?????????????@????????>????????????????0>>?P??????????????>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>???????????@>>?@???????????????????>>???????p>>???????????>?????????@????????????>????????0??????????????@????????>?????????????????@>>?`???????????????@=?p???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@?@?????????@>>?@??????????????????>?`????@>@?@???????????>?????????@????????????>???????@=>??????????????@????????>??????????????? >@>?@????????????>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>????????`>>?`????????????????p>>@>>>????????????>>???????>????????????>?????>@>??????????????>???????>>????????????`?=>? ?p?????????@>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`? ???????>>? >>? >>?????????????????`>@>?p????????????>????????????=>?@???????????????>????????????>??0?`>=?P????????>? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>?????????p>>? ??>>??? >>?p??????????????????? >=>?@??????????????>????????????=>?p????????????>????????????>>? ???@???p?>?????????? >????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p=???????????0? ????>>????? ?0???????????????????????@?0>>?@?P?????????????????>>???????>????????????>?????>@>????????????>???????>>?????????????p>?P?????@??????0??????????>?@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????=?p???????????????>>??????????????????????????????>????????????????????>?????????@????????????>???????@=?P????????????@????????>????????????????????@???????????????? >????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>????????????????>>??????????????????????????????>????????????????????>?????????@????????????>????????@?@????????????@????????>????????????????????@???????????????p>?@???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ?`????????????????? ??? ??????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>????????????????????`???????????????????>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>???????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>??????????????????????????????????????p=?`????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@?@???????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>??????????????????????????????????????>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>@????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>?????????????????????????????????????`=?`????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`? ????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>????????????????????????????????????>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>?????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>????????????????????????????????????`=?p????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p=??????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>???????????????????????????????????>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????=?p?????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>???????????????????????????????????@=?p????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>??????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>??????????????????????????????????>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ?`??????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>??????????????????????????????????@>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>@>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#?@? ?????????????????????????????????? ?`G????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Pj>>G6<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>T?@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@>T<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Pj=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? =<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?`G???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Pj=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?p#????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?0???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>T??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>T??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>T?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>T?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>T????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>T????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`G<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?Pj???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>T<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>G6?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`G<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=?Pj?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=?Pj??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>T?`G???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>?@?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????p ?0???????????????????????????????????@?p ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????`@@>‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>‚?@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>? ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>?P``????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????0<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????p ><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<? ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<? ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????>F<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????`@@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=?P``???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????0<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>F?p ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>BB??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?P``?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????>BB<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>‚????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?p ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>‚???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>F???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????>‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?P``??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????>‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????p >F<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????P``>F<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????p >‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????`@@>BB>F<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<?@??????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>T<<<<<<<<<<<<<<<<<<<<<?@??????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<?@??????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Pj<<<<<<<<<<<<<<<<<<<<<<?`G??????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#=<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<>T???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@>T<<<<<<<<<<<<<<<<<<<<<<<<? ???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Pj?@?@?>><<<<<<<<<<<<<<<<<<<<<<<<<<?`G???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`G>>G6<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Pj>G6<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?0????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#>G6<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=?????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>?????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?`G?????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<> ??????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?@??????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=?`G???????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>T?????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>T<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=?p#?????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?@?????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>?p#????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?Pj???????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`G<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>T???????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>G6<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?@??????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<> ??????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?`G?????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>?????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>?????????????????????????????????????????????????????????????????????????????????P``<<<<<<<<<<<<<<<<<<<<<>F??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?Pj????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`G><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<?P``?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#?0???????????????????> >T>T=<<<<<<<<<<<<<<<<<<<<<<<<<<<>G6????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`G? >T<<<<<<<<<<<<<<<<<<<<<<<<<?p#???????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<>F?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@=<<<<<<<<<<<<<<<<<<<<<<<?0???????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<?@?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#=<<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<>F??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<<>T????????????????????????????????????????????????????????????????????????????????0<<<<<<<<<<<<<<<<<<<<<<<>‚?p ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>T<<<<<<<<<<<<<<<<<<<<<>????????????????????????????????????????????????????????????????????????????????`@@<<<<<<<<<<<<<<<<<<<<<<<<>? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????=<<<<<<<<<<<<<<<<<<<<<<<<<=>??@?@?@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#<<<<<<<<<<<<<<<<<<<<<<?`G???????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>‚?@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<?@???????????????????????????????????????????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>?`@@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>T<<<<<<<<<<<<<<<<<<<<<?@????????????????????????????????????????????????????????????????????????????????p <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=?P``??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<?0????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=?P``?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>F?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????p =<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?P``???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????>F<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>‚???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????`@@=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????p =<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?0???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????p =<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?p ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>‚????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?`@@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>‚??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????p <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>BB???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>?@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????>‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>???????????????????? ?`@@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<>??P``???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????`@@<<<<<<<<<<<<<<<<<<<<<<<=???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????0<<<<<<<<<<<<<<<<<<<<<<<?P``???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<=?p ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<>BB?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????=<<<<<<<<<<<<<<<<<<<<<?0?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<?p ?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<=??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<>BB??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<>>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>? ?p#?????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=?????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>G6?p#??????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Pj<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>G6?p#?????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<> ?????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?@????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>G6<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>T????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?`G???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<? ???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Pj<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>T???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>T???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`G<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>T???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>T???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`G<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>T???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>T???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>G6<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????Pj=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<? ???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?`G???????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>T????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?@????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<> ?????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>G6?p#?????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#?=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>G6?p#??????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#?>G6<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=?????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p#?0?>>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>T>? ?p#?????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0>BB>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>F<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p >‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?@?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`@@=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?@???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>BB<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????P``<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?`@@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?0??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=?`@@???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????P``<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<?0????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>BB?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>BB<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>‚???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`@@=<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>‚?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>‚??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<=? ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p >‚<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>‚?p ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>??`@@???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????0>BB>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>??0?`@@???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p?@?@?@?p?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`?@?@?@?P???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????=?p????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>? ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>???????????????????????????????????@?@?@?@?@?@?@?@?p????????`?@?@?@?@?@?@?@?P??????????????????p?@?@?@?@?@?@?@?@?@?@?@?`??????????????????`?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?P?????????????????????????`?@?@?@?@?@?@?@?@?@?@?@?p???????????????????????????????????????????????????????0>@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ?`???????????????????????????????????@????????>???????????????p?>@>>?`???????????????=>?@???????????????????`>>>@??p???????????????????????????????????????????????????>?@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>????????????????????????????????????@????????>??????????????@=???????????????>?p????????????????=?@?????????????????????????????????????????????????? >???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@?@?????????>>???????????????????????@????????>????????????? >?????????????>@??????????????>? ?????????????????????@???????????????????????p>?@??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>??????????>>???????????????????????@????????>????????????`=>?@?@?@?=?0????????????>??????0>??????????????0=??@?@?@>=?`????????????????????@???????????????????????>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`? ?????p?????>>??????p?????????????????@????????>?????????????P??????p>>????????????>???????>=????????????>>?p??????P???????????????p??????@???????p???????????????p=?`??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>?????>>? ???>>???? >>?????????????????@????????>???????????>>???????? ????????????>????????p?@???????????? ???????>>?????????????0>?@????@????? >@=?`??????????????>???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p=??????@>? ?>>?? >?@????????????????@????????>???????????>?????????@????????????>?????????@????????????@????????>????????????P=>? ?p?@??`?=>@?p????????????`=?`???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????=?p?????>>>>?????????????????@????????>???????????>?????????@????????????>?????????@????????????@????????>????????????==>>>?@???????????>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>???????`>>?`?????????????????@????????>???????????>?????????@????????????>?????????@????????????@????????>?????????????p?>>? ?????????????`=?p??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ?`?????????@>>?@???????????????????@????????>???????????>?????????@????????????>????????=?????????????@????????>????????????????0>>?P??????????????>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>???????????@>>?@???????????????????>>???????p>>???????????>?????????@????????????>????????0??????????????@????????>?????????????????@>>?`???????????????@=?p???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@?@?????????@>>?@??????????????????>?`????@>@?@???????????>?????????@????????????>???????@=>??????????????@????????>??????????????? >@>?@????????????>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>????????`>>?`????????????????p>>@>>>????????????>>???????>????????????>?????>@>??????????????>???????>>????????????`?=>? ?p?????????@>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`? ???????>>? >>? >>?????????????????`>@>?p????????????>????????????=>?@???????????????>????????????>??0?`>=?P????????>? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>?????????p>>? ??>>??? >>?p??????????????????? >=>?@??????????????>????????????=>?p????????????>????????????>>? ???@???p?>?????????? >????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p=???????????0? ????>>????? ?0???????????????????????@?0>>?@?P?????????????????>>???????>????????????>?????>@>????????????>???????>>?????????????p>?P?????@??????0??????????>?@????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????=?p???????????????>>??????????????????????????????>????????????????????>?????????@????????????>???????@=?P????????????@????????>????????????????????@???????????????? >????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>????????????????>>??????????????????????????????>????????????????????>?????????@????????????>????????@?@????????????@????????>????????????????????@???????????????p>?@???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ?`????????????????? ??? ??????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>????????????????????`???????????????????>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>???????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>??????????????????????????????????????p=?`????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????@?@???????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>??????????????????????????????????????>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>@????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>?????????????????????????????????????`=?`????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????`? ????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>????????????????????????????????????>>????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>?????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>????????????????????????????????????`=?p????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????p=??????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>???????????????????????????????????>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????=?p?????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>???????????????????????????????????@=?p????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>>??????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>??????????????????????????????????>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? ?`??????????????????????????????????????????????????????>????????????????????>?????????@????????????>?????????@????????????@????????>??????????????????????????????????@>?????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>@>??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????>? ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????=>>?????????????????????????????????>>>@??P???????????????????????????????????????@>>?@????????????????????????????????????????????=?0??????????????????????????????????????????????? >@?p?????????????????????????????????????????????????>?p??????????????????????????????????????????????????>>????????????????????????????????????????????????????? >@?p?????????????????????????????????????????????????????==?`??????????????????????????????????????????????????????>?0????????????????????????????????????????????????????????>?????????????????????????????????????????????????????????@=?p?????????????????????????????????????????????????????????@???????????????????????????????????????????????????????????@=?p??????????????????????????????????????????????????????????@>???????????????????????????????????????????????????????????@?`???????????????????????????????????????????????????????????@>???????????????????????????????????????????????????????????? >???????????????????????????????????????????????????????????>? ???????????????????????????????????????????????????????????>@?@???????????????????????????????????????????????????????????`???????????????????????????????????????????????????????????>???????????????????????????????????????????????????????????P>??????????????????????????????????????????????????????????p>@>?????????????????????????????????????????????????????????p>@>????????????????????????????????????????????????????????@>>?????????????????????????????????????????????????????`? >>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????=>?????????????????????????????????>>=>??????????????????????>? ???????????????????????????????????????`? >>??????????????????????>????????????????????????????????????????????`>>??????????????????????????????????????????????????????????????????????@>@>??????????????????????>?????????????????????????????????????????????????p>>??????????????????????=?`??????????????????????????????????????????????????>>??????????????????????>????????????????????????????????????????????????????>>???????????????????????P?????????????????????????????????????????????????????>>??????????????????????>???????????????????????????????????????????????????????p>@>??????????????????????>????????????????????????????????????????????????????????P=>????????????????????????????????????????????????????????????????????????????????>????????????????????????????????????????????????????????????????????????????????>@>???????????????????????0??????????????????????????????????????????????????????????@>???????????????????????@??????????????????????????????????????????????????????????>>?????????????????????????????????????????????????????????????????????????????????? >??????????????????????????????????????????????????????????????????????????????????=>??????????????????????>???????????????????????????????????????????????????????????>>??????????????????????>???????????????????????????????????????????????????????????? >???????????????????????p???????????????????????????????????????????????????????????P>??????????????????????? ???????????????????????????????????????????????????????????>??????????????????????>???????????????????????????????????????????????????????????>@>??????????????????????? ??????????????????????????????????????????????????????????>>??????????????????????=?P?????????????????????????????????????????????????????????>>??????????????????????>@?P????????????????????????????????????????????????????????>>??????????????????????=? ????????????????????????????????????????????????????????>??????????????????????>??P?????????????????????????????????????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>?????????????????????????????????????????????>?????????????????????????????????????????????>??????????????????????? ?????????????????????>>???????????????????????@?????????????????????>>????????????????????????????????????????????>>??????????????????????>@??????????????????????>>?????????????????????????????????????????????>??????????????????????=?p??????????????????????`>??????????????????????? ???????????????????????@>??????????????????????? ????????????????????????>??????????????????????>?@????????????????????????>>??????????????????????>@>>>? ?`??????????????????????????>>??????????????????????>??P???????????????????????????????????????????????????`>??????????????????????=? ?????????????????????????????????????????????????????? >??????????????????????>@?P??????????????????????????????????????????????????????>>??????????????????????=?P???????????????????????????????????????????????????????p>??????????????????????? ????????????????????????????????????????????????????????>??????????????????????>????????????????????????????????????????????????????????>>??????????????????????? ????????????????????????????????????????????????????????0>???????????????????????p???????????????????????????????????????????????????????>>??????????????????????>???????????????????????????????????????????????????????? >??????????????????????>???????????????????????????????????????????????????????p>>?????????????????????????????????????????????????????????????????????????????>>?????????????????????????????????????????????????????????????????????????????@>???????????????????????@?????????????????????????????????????????????????????p=>???????????????????????0?????????????????????????????????????????????????????>>?????????????????????????????????????????????????????????????????????????????`=>??????????????????????????????????????????????????????????????????????????????>??????????????????????>???????????????????????????????????????????????????????>@>??????????????????????>????????????????????????????????????????????????????????@>???????????????????????P???????????????????????????????????????????????????????>>??????????????????????>????????????????????????????????????????????????????????0>??????????????????????=?`???????????????????????????????????????????????????????>>??????????????????????0>????????????????????????????????????????????????????????>??????????????????????@????????????????????????????????????????????????????????`>@??????????????????????P>??????????????????????????????????????????????????????>@??????????????????????>? ???????????????????????????????????????????????????????????????????????????>@=>????????????????????0?@?@?p????????????????????????????P??????????????????????>>>?@?????????????????????????=?@??????????????????????P>?p???????????????????????>?0??????????????????????>=?p???????????????????????????????????????????????P>???????????????????????@>???????????????????????? =?@??????????????????????`>?????????????????????????`>>???????????????????????p??????????????????????????p?0?>>>=??????????????????????>?0???????????????????????????????????????????????????`? >?`?????????????????????>>??????????????????????????????????????????????????????@>?@?????????????????????>=???????????????????????????????????????????????????????p>@??????????????????????>?0???????????????????????????????????????????????????????p>@???????????????????????>????????????????????????????????????????????????????????P>???????????????????????p???????????????????????????????????????????????????????>>???????????????????????????????????????????????????????????????????????????????`>??????????????????????=?p???????????????????????????????????????????????????????>@>??????????????????????>???????????????????????????????????????????????????????>>???????????????????????P??????????????????????????????????????????????????????? >??????????????????????>???????????????????????????????????????????????????????@>?????????????????????????????????????????????????????????????????????????????@>???????????????????????@?????????????????????????????????????????????????????@>??????????????????????>?p?????????????????????????????????????????????????????@>???????????????????????@??????????????????????????????????????????????????????@>??????????????????????>???????????????????????????????????????????????????????@>??????????????????????=?p???????????????????????????????????????????????????????>??????????????????????????????????????????????????????????????????????????????>>??????????????????????=?p???????????????????????????????????????????????????????=>??????????????????????????????????????????????????????????????????????????????? >???????????????????????`???????????????????????????????????????????????????????>>??????????????????????>????????????????????????????????????????????????????????>???????????????????????0??????????????????????????????????????????????????????? >??????????????????????=???????????????????????????????????????????????????????>??????????????????????>?????????????????????????????????????????????????????@>>??????????????????????? ?????????????????????????????@?@?@???????????????????>>>???????????????????????`?????????????????????????`>>@>??????????????????????>????????????????????????p>>??????????????????????>???????????????????????>@>??????????????????????????????????????????????>???????????????????????0??????????????????????p=>???????????????????????@??????????????????????>???????????????????????p?????????????????????>>????????????????????????????????????????????=>????????????????????????????????????????????p>??????????????????????>??????????????????????@>??????????????????????>??????????????????????@>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????`?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@? >=>??????????????????????>???????????????????????????????????????????????????????p?>??????????????????????>?????????????????????????????????????????????????????????P=>??????????????????????>@??????????????????????????????????????????????????????????P=>?????????????????????????????????????????????????????????????????????????????????0>?????????????????????????????????????????????????????????????????????????????????>>???????????????????????P???????????????????????????????????????????????????????????@>???????????????????????0???????????????????????????????????????????????????????????>>??????????????????????????????????????????????????????????????????????????????????>>??????????????????????>@????????????????????????????????????????????????????????????>???????????????????????p???????????????????????????????????????????????????????????@>??????????????????????????????????????????????????????????????????????????????????@>??????????????????????>???????????????????????????????????????????????????????????@>??????????????????????? ??????????????????????????????????????????????????????????@>??????????????????????>??????????????????????????????????????????????????????????@>????????????????????????????????????????????????????????????????????????????????@>???????????????????????P????????????????????????????????????????????????????????>??????????????????????>@?p??????????????????????????????????????????????????????>>??????????????????????>??????????????????????????????????????????????????????>>????????????????????????????????????????????????????????????????????????????@>??????????????????????? ???????????????????????????????????????????????????>>??????????????????????>??????????????????????????????????????????????????0>??????????????????????>?`???????????????????????????????????????????????P=>??????????????????????=??p????????????????????????????????????????????P=>??????????????????????=>?P????????????????????????????????????????p?>??????????????????????=>?? ?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@? >=>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??????????????????????>??@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?P??????????????????????>?`???????????????????????????????????????????????????????=? ??????????????????????????????????????????????????????????0?????????????????????????????????????????????????????????>???????????????????????????????????????????????????????????>>?p??????????????????????????????????????????????????????????>?????????????????????????????????????????????????????????????`???????????????????????????????????????????????????????????`>@????????????????????????????????????????????????????????????0>???????????????????????????????????????????????????????????>????????????????????????????????????????????????????????????>????????????????????????????????????????????????????????????@?@??????????????????????????????????????????????????????????>?@??????????????????????????????????????????????????????????`??????????????????????????????????????????????????????????>??????????????????????????????????????????????????????????@>????????????????????????????????????????????????????????p>>@???????????????????????????????????????????????????????>?`???????????????????????????????????????????????????????????????????????????????????????????????????????????? >?p??????????????????????????????????????????????????? ??????????????????????????????????????????????????? ?0???????????????????????????????????????????????p>=? ????????????????????????????????????????????? =>?`????????????????????????????????????????`?>>??@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?@?0?>>=>>>=>>>>>@>???p=?@???>?`???>>>>>>>>=>>>>>>>>>@=>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>@>>>>>>>>>>>>=>????P>???>????????>?????????@=>?P??????????????`?>????????????????????p? >>??`??????????????P>=?`???>?@??? ????????>?????????@>?p??????????????????>???????????????????????=>???????????????????p>>????@>???>?@???@????????>?????????@>?????????????????????? ????????????????????????P? ?????????????????????>>????=?`???>? ???@?@???@????????>?????????@>?p????????? >>>??p????????>?????????@>?@?????????>?????????p?>>>? ?????????p>>?????????0>???>=?@???@=????????>?????????@?????????>@=?`????????@?????????@? ????????p?@????????`=>@?????????=>????==?p???>????`? ?`>?@???@>?`? ????????>?????????@?@???????? >?????????????????@=????????>????????>? ????????@>??0>>????>?P?p>????? =?p??>>????`>?@???@>?`???>????????>?????????@?@????????>?????????????????@????????>????????>?????????@>@?p????`>=>????>??p????P=>?p???>>???p=???????`?`???`?`??????????????>?????????@?@????????>?????????????????@????????>????????>?????????@>?p??????p?0????? ???????`>? ?????`???>?0?????????????0>????????>?????????@?@????????>?????????????????@????????>????????>?????????@=>?`???????????????@>>????p=>???>>?@?????????@>????????>?????????@?@????????>?????????????????@????????p????????>?????????@>?@??????????? >@? ?????@??? >?`???????`>?`????????0=?`???????? ?@????????>?????????????????@>???????>????????>?????????@>?@????????? >>????p=>???>>?@???????????@>??????????0>>?P????????>?@????????>?????????????????@>?p??????? ????????>?????????@>?P?????????????0>?@???>? ???@>? ???????????????0>=?`??????????P?@?`??????????0?@????????@???????? ?????????????????`??????P????????????????? ????????@????????@>??p?????????????????`>=>????`>???>??????`>?@???@>?`?????>?P???????????????????? =?@????????????????????????????????????????????p?0>?????????????????????????@>??????`?>????>? ?p?????>@?@???>????`=?`??`>?@???@>?`??`=>?0???????????????p? >?@???????????????????????????????????????????????p?=?????????????????????????@?0???@>>????=>?`??>>????`=?p??>>>?@???@>>>>?`????????@>>@?@????????@???????? ?????????????????`??????P??????????@????????? ????????@????????@=?>@>????>??`???>>???p=?@???@?@?????????@????????>?????????????????@>?p????????>@????????>?????????@>????>????@?`????@???@?@?????????@????????>?????????????????@>????????>????????>?????????@>????=?`???>>???>>??>?@?????????@????????>?????????????????@????????>????????>?????????@>?????????@?@???0?@?????????@????????>?????????????????@????????>????????>?????????@=?p???>>???>?@?????????@????????>?????????????????@????????>????????>?????????@????? ? ???P?@?????????@????????>?????????????????@????????>????????>?????????@>?p???>>???>?@?????????@????????>?????????????????@????????>????????>?????????@? ????? ???`?@?????????@????????>?????????????????@????????>????????>?????????@>????p==?p????@?????????@????????>?????????????????@????????>????????>?????????@? ????????p=?@?????????@????????>?????????????????@????????>????????>?????????@>????p=?`??? ?@?????????@????????>?????????????????@????????>????????>?????????@?@???>>???>?@?????????@????????>?????????????????@????????>????????>?????????@>????`?P???0?@???>yara-4.5.3/libyara/000077500000000000000000000000001501365277300141135ustar00rootroot00000000000000yara-4.5.3/libyara/ahocorasick.c000066400000000000000000000622731501365277300165570ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include typedef struct _QUEUE_NODE { YR_AC_STATE* value; struct _QUEUE_NODE* previous; struct _QUEUE_NODE* next; } QUEUE_NODE; typedef struct _QUEUE { QUEUE_NODE* head; QUEUE_NODE* tail; } QUEUE; //////////////////////////////////////////////////////////////////////////////// // Pushes an automaton state into the tail of a queue. // // Args: // queue: Pointer to the queue. // state: Pointer to the state being pushed into the queue. // // Returns: // ERROR_SUCCESS // ERROR_INSUFFICIENT_MEMORY // static int _yr_ac_queue_push(QUEUE* queue, YR_AC_STATE* state) { QUEUE_NODE* pushed_node; pushed_node = (QUEUE_NODE*) yr_malloc(sizeof(QUEUE_NODE)); if (pushed_node == NULL) return ERROR_INSUFFICIENT_MEMORY; pushed_node->previous = queue->tail; pushed_node->next = NULL; pushed_node->value = state; if (queue->tail != NULL) queue->tail->next = pushed_node; else // queue is empty queue->head = pushed_node; queue->tail = pushed_node; return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Pops an automaton state from the head of a queue. // // Args: // queue: Pointer to the queue. // // Returns: // Pointer to the poped state. // static YR_AC_STATE* _yr_ac_queue_pop(QUEUE* queue) { YR_AC_STATE* result; QUEUE_NODE* popped_node; if (queue->head == NULL) return NULL; popped_node = queue->head; queue->head = popped_node->next; if (queue->head) queue->head->previous = NULL; else // queue is empty queue->tail = NULL; result = popped_node->value; yr_free(popped_node); return result; } //////////////////////////////////////////////////////////////////////////////// // Checks if a queue is empty. // // Args: // queue: Pointer to the queue. // // Returns: // true if queue is empty, false otherwise. // static int _yr_ac_queue_is_empty(QUEUE* queue) { return queue->head == NULL; } //////////////////////////////////////////////////////////////////////////////// // Given an automaton state and an input symbol, returns the new state // after reading the input symbol. // // Args: // state: Pointer to automaton state. // input: Input symbol. // // Returns: // Pointer to the next automaton state. // static YR_AC_STATE* _yr_ac_next_state(YR_AC_STATE* state, uint8_t input) { YR_AC_STATE* next_state = state->first_child; while (next_state != NULL) { if (next_state->input == input) return next_state; next_state = next_state->siblings; } return NULL; } //////////////////////////////////////////////////////////////////////////////// // Creates a new automaton state, the automaton will transition from // the given state to the new state after reading the input symbol. // // Args: // state: Pointer to the origin state. // input: Input symbol. // // Returns: // YR_AC_STATE* pointer to the newly allocated state or NULL in case // of error. // static YR_AC_STATE* _yr_ac_state_create(YR_AC_STATE* state, uint8_t input) { YR_AC_STATE* new_state = (YR_AC_STATE*) yr_malloc(sizeof(YR_AC_STATE)); if (new_state == NULL) return NULL; new_state->input = input; new_state->depth = state->depth + 1; new_state->matches_ref = YR_ARENA_NULL_REF; new_state->failure = NULL; new_state->t_table_slot = 0; new_state->first_child = NULL; new_state->siblings = state->first_child; state->first_child = new_state; return new_state; } //////////////////////////////////////////////////////////////////////////////// // Destroys an automaton state. // static int _yr_ac_state_destroy(YR_AC_STATE* state) { YR_AC_STATE* child_state = state->first_child; while (child_state != NULL) { YR_AC_STATE* next_child_state = child_state->siblings; _yr_ac_state_destroy(child_state); child_state = next_child_state; } yr_free(state); return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Create failure links for each automaton state. // // This function must be called after all the strings have been added to the // automaton with yr_ac_add_string. // static int _yr_ac_create_failure_links(YR_AC_AUTOMATON* automaton) { YR_AC_STATE* current_state; YR_AC_STATE* failure_state; YR_AC_STATE* temp_state; YR_AC_STATE* state; YR_AC_STATE* transition_state; YR_AC_STATE* root_state; YR_AC_MATCH* match; QUEUE queue; queue.head = NULL; queue.tail = NULL; root_state = automaton->root; // Set the failure link of root state to itself. root_state->failure = root_state; // Push root's children and set their failure link to root. state = root_state->first_child; while (state != NULL) { FAIL_ON_ERROR(_yr_ac_queue_push(&queue, state)); state->failure = root_state; state = state->siblings; } // Traverse the trie in BFS order calculating the failure link // for each state. while (!_yr_ac_queue_is_empty(&queue)) { current_state = _yr_ac_queue_pop(&queue); match = yr_arena_ref_to_ptr(automaton->arena, ¤t_state->matches_ref); if (match != NULL) { // Find the last match in the list of matches. while (match->next != NULL) match = match->next; if (match->backtrack > 0) match->next = yr_arena_ref_to_ptr( automaton->arena, &root_state->matches_ref); } else { // This state doesn't have any matches, its matches will be those // in the root state, if any. current_state->matches_ref = root_state->matches_ref; } // Iterate over all the states that the current state can transition to. transition_state = current_state->first_child; while (transition_state != NULL) { FAIL_ON_ERROR(_yr_ac_queue_push(&queue, transition_state)); failure_state = current_state->failure; while (1) { temp_state = _yr_ac_next_state(failure_state, transition_state->input); if (temp_state != NULL) { transition_state->failure = temp_state; if (YR_ARENA_IS_NULL_REF(transition_state->matches_ref)) { transition_state->matches_ref = temp_state->matches_ref; } else { match = yr_arena_ref_to_ptr( automaton->arena, &transition_state->matches_ref); assert(match != NULL); // Find the last match in the list of matches. while (match->next != NULL) match = match->next; match->next = yr_arena_ref_to_ptr( automaton->arena, &temp_state->matches_ref); } break; } else { if (failure_state == root_state) { transition_state->failure = root_state; break; } else { failure_state = failure_state->failure; } } } // while(1) transition_state = transition_state->siblings; } } // while(!__yr_ac_queue_is_empty(&queue)) return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Returns true if the transitions for state s2 are a subset of the transitions // for state s1. In other words, if at state s2 input X is accepted, it must be // accepted in s1 too. // static bool _yr_ac_transitions_subset(YR_AC_STATE* s1, YR_AC_STATE* s2) { uint8_t set[32]; YR_AC_STATE* state = s1->first_child; memset(set, 0, 32); while (state != NULL) { set[state->input / 8] |= 1 << state->input % 8; state = state->siblings; } state = s2->first_child; while (state != NULL) { if (!(set[state->input / 8] & 1 << state->input % 8)) return false; state = state->siblings; } return true; } //////////////////////////////////////////////////////////////////////////////// // Removes unnecessary failure links. // static int _yr_ac_optimize_failure_links(YR_AC_AUTOMATON* automaton) { QUEUE queue = {NULL, NULL}; // Push root's children. YR_AC_STATE* root_state = automaton->root; YR_AC_STATE* state = root_state->first_child; while (state != NULL) { FAIL_ON_ERROR(_yr_ac_queue_push(&queue, state)); state = state->siblings; } while (!_yr_ac_queue_is_empty(&queue)) { YR_AC_STATE* current_state = _yr_ac_queue_pop(&queue); if (current_state->failure != root_state) { if (_yr_ac_transitions_subset(current_state, current_state->failure)) current_state->failure = current_state->failure->failure; } // Push children of current_state state = current_state->first_child; while (state != NULL) { FAIL_ON_ERROR(_yr_ac_queue_push(&queue, state)); state = state->siblings; } } return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Find a place within the automaton's transition table where the transitions // for the given state can be put. The function first create a bitmask for the // state's transition table, then searches for an offset within the automaton's // bitmask where the state's bitmask can be put without bit collisions. // static int _yr_ac_find_suitable_transition_table_slot( YR_AC_AUTOMATON* automaton, YR_ARENA* arena, YR_AC_STATE* state, uint32_t* slot) { // The state's transition table has 257 entries, 1 for the failure link and // 256 for each possible input byte, so the state's bitmask has 257 bits. YR_BITMASK state_bitmask[YR_BITMASK_SIZE(257)]; YR_AC_STATE* child_state = state->first_child; // Start with all bits set to zero. yr_bitmask_clear_all(state_bitmask); // The first slot in the transition table is for the state's failure link, // so the first bit in the bitmask must be set to one. yr_bitmask_set(state_bitmask, 0); while (child_state != NULL) { yr_bitmask_set(state_bitmask, child_state->input + 1); child_state = child_state->siblings; } *slot = yr_bitmask_find_non_colliding_offset( automaton->bitmask, state_bitmask, automaton->tables_size, 257, &automaton->t_table_unused_candidate); // Make sure that we are not going beyond the maximum size of the transition // table, starting at the slot found there must be at least 257 other slots // for accommodating the state's transition table. assert(*slot + 257 < YR_AC_MAX_TRANSITION_TABLE_SIZE); if (*slot > automaton->tables_size - 257) { FAIL_ON_ERROR(yr_arena_allocate_zeroed_memory( arena, YR_AC_TRANSITION_TABLE, 257 * sizeof(YR_AC_TRANSITION), NULL)); FAIL_ON_ERROR(yr_arena_allocate_zeroed_memory( arena, YR_AC_STATE_MATCHES_TABLE, 257 * sizeof(uint8_t*), NULL)); size_t bm_len = YR_BITMASK_SIZE(automaton->tables_size) * sizeof(YR_BITMASK); size_t bm_len_incr = YR_BITMASK_SIZE(257) * sizeof(YR_BITMASK); automaton->bitmask = yr_realloc(automaton->bitmask, bm_len + bm_len_incr); if (automaton->bitmask == NULL) return ERROR_INSUFFICIENT_MEMORY; memset((uint8_t*) automaton->bitmask + bm_len, 0, bm_len_incr); automaton->tables_size += 257; } return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Builds the transition table for the automaton. The transition table (T) is a // large array of 32-bits integers. Each state in the automaton is represented // by an index S within the array. The integer stored in T[S] is the failure // link for state S, it contains the index of the next state when no valid // transition exists for the next input byte. // // At position T[S+1+B] (where B is a byte) we can find the transition (if any) // that must be followed from state S if the next input is B. The value in // T[S+1+B] contains the index for next state or zero. A zero value means that // no valid transition exists from state S when next input is B, and the failure // link must be used instead. // // The transition table for state S starts at T[S] and spans the next 257 // slots in the array (1 for the failure link and 256 for all the possible // transitions). But many of those slots are for invalid transitions, so // the transitions for multiple states can be interleaved as long as they don't // collide. For example, instead of having this transition table with state S1 // and S2 separated by a large number of slots: // // S1 S2 // +------+------+------+------+-- ~ --+------+------+------+-- ~ --+ // | FLS1 | X | - | - | - | Y | FLS2 | Z | - | // +------+------+------+------+-- ~ --+------+------+------+-- ~ --+ // // We can interleave the transitions for states S1 and S2 and get this other // transition table, which is more compact: // // S1 S2 // +------+------+------+------+-- ~ --+------+ // | FLS1 | X | FLS2 | Z | - | Y | // +------+------+------+------+-- ~ --+------+ // // And how do we know that transition Z belongs to state S2 and not S1? Or that // transition Y belongs to S1 and not S2? Because each slot of the array not // only contains the index for the state where the transition points to, it // also contains the offset of the transition relative to its owner state. So, // the value for the owner offset would be 1 for transitions X, because X // belongs to state S1 and it's located 1 position away from S1. The same occurs // for Z, it belongs to S2 and it's located one position away from S2 so its // owner offset is 1. If we are in S1 and next byte is 2, we are going to read // the transition at T[S1+1+2] which is Z. But we know that transition Z is not // a valid transition for state S1 because the owner offset for Z is 1 not 3. // // Each 32-bit slot in the transition table has 23 bits for storing the index // of the target state and 9 bits for storing the offset of the slot relative // to its own state. The offset can be any value from 0 to 256, both inclusive, // hence 9 bits are required for it. The layout for the slot goes like: // // 32 23 0 // +-----------------------+---------+ // | Target state's index | Offset | // +-----------------------+---------+ // // A more detailed description can be found in: http://goo.gl/lE6zG // static int _yr_ac_build_transition_table(YR_AC_AUTOMATON* automaton) { YR_AC_TRANSITION* t_table; uint32_t* m_table; YR_AC_STATE* state; YR_AC_STATE* child_state; YR_AC_STATE* root_state = automaton->root; uint32_t slot; QUEUE queue = {NULL, NULL}; // Both t_table and m_table have 512 slots initially, which is enough for the // root node's transition table. automaton->tables_size = 512; automaton->bitmask = yr_calloc( YR_BITMASK_SIZE(automaton->tables_size), sizeof(YR_BITMASK)); if (automaton->bitmask == NULL) return ERROR_INSUFFICIENT_MEMORY; FAIL_ON_ERROR(yr_arena_allocate_zeroed_memory( automaton->arena, YR_AC_TRANSITION_TABLE, automaton->tables_size * sizeof(YR_AC_TRANSITION), NULL)); FAIL_ON_ERROR(yr_arena_allocate_zeroed_memory( automaton->arena, YR_AC_STATE_MATCHES_TABLE, automaton->tables_size * sizeof(uint32_t), NULL)); t_table = yr_arena_get_ptr(automaton->arena, YR_AC_TRANSITION_TABLE, 0); m_table = yr_arena_get_ptr(automaton->arena, YR_AC_STATE_MATCHES_TABLE, 0); // The failure link for the root node points to itself. t_table[0] = YR_AC_MAKE_TRANSITION(0, 0); // Initialize the entry corresponding to the root node in the match table. // Entries in this table are the index within YR_AC_MATCH_POOL where resides // the YR_AC_MATCH structure that corresponds to the head of the matches list // for the node. The indexes start counting at 1, the zero is used for // indicating that the node has no associated matches. if (!YR_ARENA_IS_NULL_REF(root_state->matches_ref)) m_table[0] = root_state->matches_ref.offset / sizeof(YR_AC_MATCH) + 1; // Mark the first slot in the transition table as used. yr_bitmask_set(automaton->bitmask, 0); // Index 0 is for root node. Unused indexes start at 1. automaton->t_table_unused_candidate = 1; child_state = root_state->first_child; while (child_state != NULL) { // Each state stores its slot number. child_state->t_table_slot = child_state->input + 1; t_table[child_state->input + 1] = YR_AC_MAKE_TRANSITION( 0, child_state->input + 1); yr_bitmask_set(automaton->bitmask, child_state->input + 1); FAIL_ON_ERROR(_yr_ac_queue_push(&queue, child_state)); child_state = child_state->siblings; } while (!_yr_ac_queue_is_empty(&queue)) { state = _yr_ac_queue_pop(&queue); FAIL_ON_ERROR(_yr_ac_find_suitable_transition_table_slot( automaton, automaton->arena, state, &slot)); // _yr_ac_find_suitable_transition_table_slot can allocate more space in // both tables and cause the tables to be moved to a different memory // location, we must get their up-to-date addresses. t_table = yr_arena_get_ptr(automaton->arena, YR_AC_TRANSITION_TABLE, 0); m_table = yr_arena_get_ptr(automaton->arena, YR_AC_STATE_MATCHES_TABLE, 0); t_table[state->t_table_slot] |= (slot << YR_AC_SLOT_OFFSET_BITS); t_table[slot] = YR_AC_MAKE_TRANSITION(state->failure->t_table_slot, 0); // The match table is an array of indexes within YR_AC_MATCHES_POOL. The // N-th item in the array is the index for the YR_AC_MATCH structure that // represents the head of the matches list for state N. The indexes start // at 1, the 0 indicates that there are no matches for the state. if (YR_ARENA_IS_NULL_REF(state->matches_ref)) m_table[slot] = 0; else m_table[slot] = state->matches_ref.offset / sizeof(YR_AC_MATCH) + 1; state->t_table_slot = slot; yr_bitmask_set(automaton->bitmask, slot); // Push children of current_state child_state = state->first_child; while (child_state != NULL) { child_state->t_table_slot = slot + child_state->input + 1; t_table[child_state->t_table_slot] = YR_AC_MAKE_TRANSITION( 0, child_state->input + 1); yr_bitmask_set(automaton->bitmask, child_state->t_table_slot); FAIL_ON_ERROR(_yr_ac_queue_push(&queue, child_state)); child_state = child_state->siblings; } } return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Prints automaton state for debug purposes. This function is invoked by // yr_ac_print_automaton, is not intended to be used stand-alone. // static void _yr_ac_print_automaton_state( YR_AC_AUTOMATON* automaton, YR_AC_STATE* state) { int child_count; YR_AC_MATCH* match; YR_AC_STATE* child_state; for (int i = 0; i < state->depth; i++) printf(" "); child_state = state->first_child; child_count = 0; while (child_state != NULL) { child_count++; child_state = child_state->siblings; } printf( "%p childs:%d depth:%d failure:%p", state, child_count, state->depth, state->failure); match = yr_arena_ref_to_ptr(automaton->arena, &state->matches_ref); while (match != NULL) { printf("\n"); for (int i = 0; i < state->depth + 1; i++) printf(" "); printf("%s = ", match->string->identifier); if (STRING_IS_HEX(match->string)) { printf("{ "); for (int i = 0; i < yr_min(match->string->length, 10); i++) printf("%02x ", match->string->string[i]); printf("}"); } else if (STRING_IS_REGEXP(match->string)) { printf("/"); for (int i = 0; i < yr_min(match->string->length, 10); i++) printf("%c", match->string->string[i]); printf("/"); } else { printf("\""); for (int i = 0; i < yr_min(match->string->length, 10); i++) printf("%c", match->string->string[i]); printf("\""); } match = match->next; } printf("\n"); child_state = state->first_child; while (child_state != NULL) { _yr_ac_print_automaton_state(automaton, child_state); child_state = child_state->siblings; } } //////////////////////////////////////////////////////////////////////////////// // Creates a new automaton // int yr_ac_automaton_create(YR_ARENA* arena, YR_AC_AUTOMATON** automaton) { YR_AC_AUTOMATON* new_automaton; YR_AC_STATE* root_state; new_automaton = (YR_AC_AUTOMATON*) yr_malloc(sizeof(YR_AC_AUTOMATON)); root_state = (YR_AC_STATE*) yr_malloc(sizeof(YR_AC_STATE)); if (new_automaton == NULL || root_state == NULL) { yr_free(new_automaton); yr_free(root_state); return ERROR_INSUFFICIENT_MEMORY; } root_state->depth = 0; root_state->matches_ref = YR_ARENA_NULL_REF; root_state->failure = NULL; root_state->first_child = NULL; root_state->siblings = NULL; root_state->t_table_slot = 0; new_automaton->arena = arena; new_automaton->root = root_state; new_automaton->bitmask = NULL; new_automaton->tables_size = 0; *automaton = new_automaton; return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Destroys automaton // int yr_ac_automaton_destroy(YR_AC_AUTOMATON* automaton) { _yr_ac_state_destroy(automaton->root); yr_free(automaton->bitmask); yr_free(automaton); return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Adds a string to the automaton. This function is invoked once for each // string defined in the rules. // int yr_ac_add_string( YR_AC_AUTOMATON* automaton, YR_STRING* string, uint32_t string_idx, YR_ATOM_LIST_ITEM* atom, YR_ARENA* arena) { while (atom != NULL) { YR_AC_STATE* state = automaton->root; for (int i = 0; i < atom->atom.length; i++) { YR_AC_STATE* next_state = _yr_ac_next_state(state, atom->atom.bytes[i]); if (next_state == NULL) { next_state = _yr_ac_state_create(state, atom->atom.bytes[i]); if (next_state == NULL) return ERROR_INSUFFICIENT_MEMORY; } state = next_state; } YR_ARENA_REF new_match_ref; FAIL_ON_ERROR(yr_arena_allocate_struct( arena, YR_AC_STATE_MATCHES_POOL, sizeof(YR_AC_MATCH), &new_match_ref, offsetof(YR_AC_MATCH, string), offsetof(YR_AC_MATCH, forward_code), offsetof(YR_AC_MATCH, backward_code), offsetof(YR_AC_MATCH, next), EOL)); YR_AC_MATCH* new_match = yr_arena_ref_to_ptr(arena, &new_match_ref); new_match->backtrack = state->depth + atom->backtrack; new_match->string = yr_arena_get_ptr( arena, YR_STRINGS_TABLE, string_idx * sizeof(struct YR_STRING)); new_match->forward_code = yr_arena_ref_to_ptr( arena, &atom->forward_code_ref); new_match->backward_code = yr_arena_ref_to_ptr( arena, &atom->backward_code_ref); // Add newly created match to the list of matches for the state. new_match->next = yr_arena_ref_to_ptr(arena, &state->matches_ref); state->matches_ref = new_match_ref; atom = atom->next; } return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Compiles the Aho-Corasick automaton, the resulting data structures are // are written in the provided arena. // int yr_ac_compile(YR_AC_AUTOMATON* automaton, YR_ARENA* arena) { FAIL_ON_ERROR(_yr_ac_create_failure_links(automaton)); FAIL_ON_ERROR(_yr_ac_optimize_failure_links(automaton)); FAIL_ON_ERROR(_yr_ac_build_transition_table(automaton)); return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Prints automaton for debug purposes. // void yr_ac_print_automaton(YR_AC_AUTOMATON* automaton) { printf("-------------------------------------------------------\n"); _yr_ac_print_automaton_state(automaton, automaton->root); printf("-------------------------------------------------------\n"); } yara-4.5.3/libyara/arena.c000066400000000000000000000506531501365277300153560ustar00rootroot00000000000000/* Copyright (c) 2020. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include typedef struct YR_ARENA_FILE_HEADER YR_ARENA_FILE_HEADER; typedef struct YR_ARENA_FILE_BUFFER YR_ARENA_FILE_BUFFER; #pragma pack(push) #pragma pack(1) struct YR_ARENA_FILE_HEADER { uint8_t magic[4]; uint8_t version; uint8_t num_buffers; }; struct YR_ARENA_FILE_BUFFER { uint64_t offset; uint32_t size; }; #pragma pack(pop) //////////////////////////////////////////////////////////////////////////////// // Tells the arena that certain offsets within a buffer contain relocatable // pointers. The offsets are passed as a vararg list where the end of the // list is indicated by the special value EOL (-1), offsets in the list are // relative to base_offset, which in turns is relative to the beginning of the // buffer. // // Args: // arena: Pointer the arena. // buffer_id: Buffer number. // base_offset: Base offset. // offsets: List of offsets relative to base offset. // // Returns: // ERROR_SUCCESS // ERROR_INSUFFICIENT_MEMORY // static int _yr_arena_make_ptr_relocatable( YR_ARENA* arena, uint32_t buffer_id, yr_arena_off_t base_offset, va_list offsets) { size_t offset; int result = ERROR_SUCCESS; // The argument to va_arg is size_t because the offsets passed to this // function are obtained with offsetof(). offset = va_arg(offsets, size_t); while (offset != EOL) { YR_RELOC* reloc = (YR_RELOC*) yr_malloc(sizeof(YR_RELOC)); if (reloc == NULL) return ERROR_INSUFFICIENT_MEMORY; reloc->buffer_id = buffer_id; reloc->offset = base_offset + (yr_arena_off_t) offset; reloc->next = NULL; if (arena->reloc_list_head == NULL) arena->reloc_list_head = reloc; if (arena->reloc_list_tail != NULL) arena->reloc_list_tail->next = reloc; arena->reloc_list_tail = reloc; offset = va_arg(offsets, size_t); } return result; } // Flags for _yr_arena_allocate_memory. #define YR_ARENA_ZERO_MEMORY 1 //////////////////////////////////////////////////////////////////////////////// // Allocates memory in a buffer within the arena. // // Args: // arena: Pointer to the arena. // flags: Flags. The only supported flag so far is YR_ARENA_ZERO_MEMORY. // buffer_id: Buffer number. // size : Size of the region to be allocated. // [out] ref: Pointer to a YR_ARENA_REF that will be updated with the // reference to the newly allocated region. The pointer can be // NULL. // Returns: // ERROR_SUCCESS // ERROR_INVALID_ARGUMENT // ERROR_INSUFFICIENT_MEMORY // static int _yr_arena_allocate_memory( YR_ARENA* arena, int flags, uint32_t buffer_id, size_t size, YR_ARENA_REF* ref) { if (buffer_id > arena->num_buffers) return ERROR_INVALID_ARGUMENT; YR_ARENA_BUFFER* b = &arena->buffers[buffer_id]; // If the new data doesn't fit in the remaining space the buffer must be // re-sized. This implies moving the buffer to a different memory location // and adjusting the pointers listed in the relocation list. if (b->size - b->used < size) { size_t new_size = (b->size == 0) ? arena->initial_buffer_size : b->size * 2; while (new_size < b->used + size) new_size *= 2; // Make sure that buffer size if not larger than 4GB. if (new_size > 1ULL << 32) return ERROR_INSUFFICIENT_MEMORY; uint8_t* new_data = yr_realloc(b->data, new_size); if (new_data == NULL) return ERROR_INSUFFICIENT_MEMORY; // When yr_realloc uses the Windows API (HeapAlloc, HeapReAlloc) it is not // necessary to set the memory to zero because the API is called with the // HEAP_ZERO_MEMORY flag. #if !defined(_WIN32) && !defined(__CYGWIN__) if (flags & YR_ARENA_ZERO_MEMORY) memset(new_data + b->used, 0, new_size - b->used); #endif // Fix pointers in the relocation list if the old buffer was not empty // and it was actually moved by yr_realloc. if (b->data != NULL && b->data != new_data) { YR_RELOC* reloc = arena->reloc_list_head; while (reloc != NULL) { // If the reloc entry is for the same buffer that is being relocated, // the base pointer that we use to access the buffer must be new_data // as arena->buffers[reloc->buffer_id].data (which is the same than // b->data) can't be accessed anymore after the call to yr_realloc. uint8_t* base = buffer_id == reloc->buffer_id ? new_data : arena->buffers[reloc->buffer_id].data; // reloc_address holds the address inside the buffer where the pointer // to be relocated resides. void** reloc_address = (void**) (base + reloc->offset); // reloc_target is the value of the relocatable pointer. void* reloc_target = *reloc_address; if ((uint8_t*) reloc_target >= b->data && (uint8_t*) reloc_target < b->data + b->used) { // reloc_target points to some data inside the buffer being moved, so // the pointer needs to be adjusted. *reloc_address = (uint8_t*) reloc_target - b->data + new_data; } reloc = reloc->next; } } b->size = new_size; b->data = new_data; } if (ref != NULL) { ref->buffer_id = buffer_id; ref->offset = (uint32_t) b->used; } b->used += size; return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Creates an arena with the specified number of buffers. // // Args: // num_buffers: Number of buffers. // initial_buffer_size: Initial size of each buffer. // [out] arena: Address of a YR_ARENA* pointer that will receive the address // of the newly created arena. // Returns: // ERROR_SUCCESS // ERROR_INSUFFICIENT_MEMORY // int yr_arena_create( uint32_t num_buffers, size_t initial_buffer_size, YR_ARENA** arena) { YR_ARENA* new_arena = (YR_ARENA*) yr_calloc(1, sizeof(YR_ARENA)); if (new_arena == NULL) return ERROR_INSUFFICIENT_MEMORY; new_arena->xrefs = 1; new_arena->num_buffers = num_buffers; new_arena->initial_buffer_size = initial_buffer_size; *arena = new_arena; return ERROR_SUCCESS; } void yr_arena_acquire(YR_ARENA* arena) { arena->xrefs++; } //////////////////////////////////////////////////////////////////////////////// // Releases the arena. // // Decrements the cross-references counter for the arena, if the number of // cross-references reaches zero the arena is destroyed and all its resources // are freed. // // Args: // arena :Pointer to the arena. // // Returns: // ERROR_SUCCESS // ERROR_INSUFFICIENT_MEMORY // int yr_arena_release(YR_ARENA* arena) { arena->xrefs--; if (arena->xrefs > 0) return ERROR_SUCCESS; for (uint32_t i = 0; i < arena->num_buffers; i++) { if (arena->buffers[i].data != NULL) yr_free(arena->buffers[i].data); } YR_RELOC* reloc = arena->reloc_list_head; while (reloc != NULL) { YR_RELOC* next = reloc->next; yr_free(reloc); reloc = next; } yr_free(arena); return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Allocates memory in a buffer within the arena. // // Args: // arena: Pointer to the arena. // buffer_id: Buffer number. // size : Size of the region to be allocated. // [out] offset: Pointer to a variable where the function puts the offset // within the buffer of the allocated region. The pointer can // be NULL. // Returns: // ERROR_SUCCESS // ERROR_INVALID_ARGUMENT // ERROR_INSUFFICIENT_MEMORY // int yr_arena_allocate_memory( YR_ARENA* arena, uint32_t buffer_id, size_t size, YR_ARENA_REF* ref) { return _yr_arena_allocate_memory(arena, 0, buffer_id, size, ref); } //////////////////////////////////////////////////////////////////////////////// // Allocates memory in a buffer within the arena and fill it with zeroes. // // Args: // arena: Pointer to the arena. // buffer_id: Buffer number. // size : Size of the region to be allocated. // [out] offset: Pointer to a variable where the function puts the offset // within the buffer of the allocated region. The pointer can // be NULL. // Returns: // ERROR_SUCCESS // ERROR_INVALID_ARGUMENT // ERROR_INSUFFICIENT_MEMORY // int yr_arena_allocate_zeroed_memory( YR_ARENA* arena, uint32_t buffer_id, size_t size, YR_ARENA_REF* ref) { return _yr_arena_allocate_memory( arena, YR_ARENA_ZERO_MEMORY, buffer_id, size, ref); } //////////////////////////////////////////////////////////////////////////////// // Allocates a structure within the arena. This function is similar to // yr_arena_allocate_memory but additionally receives a variable-length // list of offsets within the structure where pointers reside. This allows // the arena to keep track of pointers that must be adjusted when memory // is relocated. This is an example on how to invoke this function: // // yr_arena_allocate_struct( // arena, // 0, // sizeof(MY_STRUCTURE), // &ref, // offsetof(MY_STRUCTURE, field_1), // offsetof(MY_STRUCTURE, field_2), // .. // offsetof(MY_STRUCTURE, field_N), // EOL); // // Args: // arena: Pointer to the arena. // buffer_id: Buffer number. // size: Size of the region to be allocated. // [out] ref: Pointer to a reference that will point to the newly allocated // structure when the function returns. The pointer can be NULL // if you don't need the reference. // ... Variable number of offsets relative to the beginning of the struct. // These offsets are of type size_t. // // Returns: // ERROR_SUCCESS // ERROR_INVALID_ARGUMENT // ERROR_INSUFFICIENT_MEMORY // int yr_arena_allocate_struct( YR_ARENA* arena, uint32_t buffer_id, size_t size, YR_ARENA_REF* ref, ...) { YR_ARENA_REF r; int result = _yr_arena_allocate_memory( arena, YR_ARENA_ZERO_MEMORY, buffer_id, size, &r); if (result != ERROR_SUCCESS) return result; va_list field_offsets; va_start(field_offsets, ref); result = _yr_arena_make_ptr_relocatable( arena, buffer_id, r.offset, field_offsets); va_end(field_offsets); if (result == ERROR_SUCCESS && ref != NULL) { ref->buffer_id = r.buffer_id; ref->offset = r.offset; } return result; } void* yr_arena_get_ptr( YR_ARENA* arena, uint32_t buffer_id, yr_arena_off_t offset) { assert(buffer_id < arena->num_buffers); assert(offset <= arena->buffers[buffer_id].used); if (arena->buffers[buffer_id].data == NULL) return NULL; return arena->buffers[buffer_id].data + offset; } yr_arena_off_t yr_arena_get_current_offset(YR_ARENA* arena, uint32_t buffer_id) { assert(buffer_id < arena->num_buffers); return (yr_arena_off_t) arena->buffers[buffer_id].used; } int yr_arena_ptr_to_ref(YR_ARENA* arena, const void* address, YR_ARENA_REF* ref) { *ref = YR_ARENA_NULL_REF; if (address == NULL) return 1; for (uint32_t i = 0; i < arena->num_buffers; ++i) { // If the buffer is completetly empty, skip it. if (arena->buffers[i].data == NULL) continue; // If the address falls within the limits of the buffer, then we found // the buffer that contains the data and return a reference to it. if ((uint8_t*) address >= arena->buffers[i].data && (uint8_t*) address < arena->buffers[i].data + arena->buffers[i].used) { ref->buffer_id = i; ref->offset = (yr_arena_off_t) ((uint8_t*) address - arena->buffers[i].data); return 1; } } return 0; } void* yr_arena_ref_to_ptr(YR_ARENA* arena, YR_ARENA_REF* ref) { if (YR_ARENA_IS_NULL_REF(*ref)) return NULL; #if defined(__arm__) YR_ARENA_REF tmp_ref; memcpy(&tmp_ref, ref, sizeof(YR_ARENA_REF)); ref = &tmp_ref; #endif return yr_arena_get_ptr(arena, ref->buffer_id, ref->offset); } //////////////////////////////////////////////////////////////////////////////// // Tells the arena that certain addresses contains a relocatable pointer. // // Args: // arena: Pointer to the arena. // buffer_id: Buffer number. // ... : Variable number of size_t arguments with offsets within the buffer. // // Returns: // ERROR_SUCCESS if succeed or the corresponding error code otherwise. // int yr_arena_make_ptr_relocatable(YR_ARENA* arena, uint32_t buffer_id, ...) { int result; va_list offsets; va_start(offsets, buffer_id); result = _yr_arena_make_ptr_relocatable(arena, buffer_id, 0, offsets); va_end(offsets); return result; } int yr_arena_write_data( YR_ARENA* arena, uint32_t buffer_id, const void* data, size_t size, YR_ARENA_REF* ref) { YR_ARENA_REF r; // Allocate space in the buffer. FAIL_ON_ERROR(_yr_arena_allocate_memory(arena, 0, buffer_id, size, &r)); // Copy the data into the allocated space. memcpy(arena->buffers[buffer_id].data + r.offset, data, size); if (ref != NULL) { ref->buffer_id = r.buffer_id; ref->offset = r.offset; } return ERROR_SUCCESS; } int yr_arena_write_string( YR_ARENA* arena, uint32_t buffer_id, const char* string, YR_ARENA_REF* ref) { return yr_arena_write_data(arena, buffer_id, string, strlen(string) + 1, ref); } int yr_arena_write_uint32( YR_ARENA* arena, uint32_t buffer_id, uint32_t integer, YR_ARENA_REF* ref) { return yr_arena_write_data(arena, buffer_id, &integer, sizeof(integer), ref); } int yr_arena_load_stream(YR_STREAM* stream, YR_ARENA** arena) { YR_ARENA_FILE_HEADER hdr; if (yr_stream_read(&hdr, sizeof(hdr), 1, stream) != 1) return ERROR_INVALID_FILE; if (hdr.magic[0] != 'Y' || hdr.magic[1] != 'A' || hdr.magic[2] != 'R' || hdr.magic[3] != 'A') { return ERROR_INVALID_FILE; } if (hdr.version != YR_ARENA_FILE_VERSION) return ERROR_UNSUPPORTED_FILE_VERSION; if (hdr.num_buffers > YR_MAX_ARENA_BUFFERS) return ERROR_INVALID_FILE; YR_ARENA_FILE_BUFFER buffers[YR_MAX_ARENA_BUFFERS]; size_t read = yr_stream_read( buffers, sizeof(buffers[0]), hdr.num_buffers, stream); if (read != hdr.num_buffers) return ERROR_CORRUPT_FILE; YR_ARENA* new_arena; FAIL_ON_ERROR(yr_arena_create(hdr.num_buffers, 10485, &new_arena)) for (int i = 0; i < hdr.num_buffers; ++i) { if (buffers[i].size == 0) continue; YR_ARENA_REF ref; FAIL_ON_ERROR_WITH_CLEANUP( yr_arena_allocate_memory(new_arena, i, buffers[i].size, &ref), yr_arena_release(new_arena)) void* ptr = yr_arena_get_ptr(new_arena, i, ref.offset); if (yr_stream_read(ptr, buffers[i].size, 1, stream) != 1) { yr_arena_release(new_arena); return ERROR_CORRUPT_FILE; } } YR_ARENA_REF reloc_ref; while (yr_stream_read(&reloc_ref, sizeof(reloc_ref), 1, stream) == 1) { YR_ARENA_BUFFER* b = &new_arena->buffers[reloc_ref.buffer_id]; if (reloc_ref.buffer_id >= new_arena->num_buffers || reloc_ref.offset > b->used - sizeof(void*) || b->data == NULL) { yr_arena_release(new_arena); return ERROR_CORRUPT_FILE; } YR_ARENA_REF ref; memcpy(&ref, b->data + reloc_ref.offset, sizeof(ref)); void* reloc_ptr = yr_arena_ref_to_ptr(new_arena, &ref); memcpy(b->data + reloc_ref.offset, &reloc_ptr, sizeof(reloc_ptr)); FAIL_ON_ERROR_WITH_CLEANUP( yr_arena_make_ptr_relocatable( new_arena, reloc_ref.buffer_id, reloc_ref.offset, EOL), yr_arena_release(new_arena)) } *arena = new_arena; return ERROR_SUCCESS; } int yr_arena_save_stream(YR_ARENA* arena, YR_STREAM* stream) { YR_ARENA_FILE_HEADER hdr; hdr.magic[0] = 'Y'; hdr.magic[1] = 'A'; hdr.magic[2] = 'R'; hdr.magic[3] = 'A'; hdr.version = YR_ARENA_FILE_VERSION; hdr.num_buffers = arena->num_buffers; if (yr_stream_write(&hdr, sizeof(hdr), 1, stream) != 1) return ERROR_WRITING_FILE; // The first buffer in the file is after the header and the buffer table, // calculate its offset accordingly. uint64_t offset = sizeof(YR_ARENA_FILE_HEADER) + sizeof(YR_ARENA_FILE_BUFFER) * arena->num_buffers; for (uint32_t i = 0; i < arena->num_buffers; ++i) { YR_ARENA_FILE_BUFFER buffer = { .offset = offset, .size = (uint32_t) arena->buffers[i].used, }; if (yr_stream_write(&buffer, sizeof(buffer), 1, stream) != 1) return ERROR_WRITING_FILE; offset += buffer.size; } // Iterate the relocation list and replace all the relocatable pointers by // references to the buffer and offset where they are pointing to. All // relocatable pointers are expected to be null or point to data stored in // some of the arena's buffers. If a relocatable pointer points outside the // arena that's an error. YR_RELOC* reloc = arena->reloc_list_head; while (reloc != NULL) { // reloc_ptr is the pointer that will be replaced by the reference. void* reloc_ptr; // Move the pointer from the buffer to reloc_ptr. memcpy( &reloc_ptr, arena->buffers[reloc->buffer_id].data + reloc->offset, sizeof(reloc_ptr)); YR_ARENA_REF ref; #if !defined(NDEBUG) int found = yr_arena_ptr_to_ref(arena, reloc_ptr, &ref); // yr_arena_ptr_to_ref returns 0 if the relocatable pointer is pointing // outside the arena, this should not happen. assert(found); #else yr_arena_ptr_to_ref(arena, reloc_ptr, &ref); #endif // Replace the relocatable pointer with a reference that holds information // about the buffer and offset where the relocatable pointer is pointing to. memcpy( arena->buffers[reloc->buffer_id].data + reloc->offset, &ref, sizeof(ref)); reloc = reloc->next; } // Now that all relocatable pointers are converted to references, write the // buffers. for (uint32_t i = 0; i < arena->num_buffers; ++i) { YR_ARENA_BUFFER* b = &arena->buffers[i]; if (b->used > 0) if (yr_stream_write(b->data, b->used, 1, stream) != 1) return ERROR_WRITING_FILE; } // Write the relocation list and restore the pointers back. reloc = arena->reloc_list_head; while (reloc != NULL) { YR_ARENA_REF ref = { .buffer_id = reloc->buffer_id, .offset = reloc->offset, }; // Write the relocation entry, which consists in a reference to the place // where the pointer that needs to be relocated is stored. if (yr_stream_write(&ref, sizeof(ref), 1, stream) != 1) return ERROR_WRITING_FILE; // Move the reference that is going to be replaced by the corresponding // pointer to the ref variable. Notice that ref is being reused for a // different reference here. memcpy( &ref, arena->buffers[reloc->buffer_id].data + reloc->offset, sizeof(ref)); // Convert the reference to its corresponding pointer. void* reloc_ptr = yr_arena_ref_to_ptr(arena, &ref); // Copy the pointer back to where the reference was stored. memcpy( arena->buffers[reloc->buffer_id].data + reloc->offset, &reloc_ptr, sizeof(reloc_ptr)); reloc = reloc->next; } return ERROR_SUCCESS; } yara-4.5.3/libyara/atoms.c000066400000000000000000001237101501365277300154060ustar00rootroot00000000000000/* Copyright (c) 2013-2018. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* This module handles atom extraction from regexps and hex strings. Atoms are undivided substrings found in a regexps and hex strings. Let's consider this hex string: { 01 02 03 04 05 ?? 06 07 08 [1-2] 09 0A } In the above string, byte sequences 0102030405, 060708 and 090A are atoms. Similarly, in this regexp: /abc.*ed[0-9]+fgh/ The strings "abc", "ed" and "fgh" are atoms. When searching for regexps/hex strings matching a file, YARA uses these atoms to find locations inside the file where the regexp/hex string could match. If the atom "abc" is found somewhere inside the file, there is a chance for /abc.*ed[0-9]+fgh/ to match the file, if "abc" doesn't appear in the file there's no chance for the regexp to match. When the atom is found in the file YARA proceeds to fully evaluate the regexp/hex string to determine if it's actually a match. For each regexp/hex string YARA extracts one or more atoms. Sometimes a single atom is enough (like in the previous example "abc" is enough for finding /abc.*ed[0-9]+fgh/), but sometimes a single atom isn't enough like in the regexp /(abc|efg)/. In this case YARA must search for both "abc" AND "efg" and fully evaluate the regexp whenever one of these atoms is found. In the regexp /Look(at|into)this/ YARA can search for "Look", or search for "this", or search for both "at" and "into". This is what we call an atoms tree, because it can be represented by the following tree structure: -OR |- "Look" | |- AND | | | |- "at" | - "into" | - "this" From an atom tree YARA chooses the best combination, trying to minimize the number of required atoms, but also using high quality atoms (long atoms with not too many zeroes and a bit of byte diversity). In the previous example YARA will end up using the "Look" atom alone, but in /a(bcd|efg)h/ atoms "bcd" and "efg" will be used because "a" and "h" are too short. */ #include #include #include #include #include #include #include #include #include #include //////////////////////////////////////////////////////////////////////////////// // Returns a numeric value indicating the quality of an atom. The quality // depends on some characteristics of the atom, including its length, number // of very common bytes like 00 and FF and number of unique distinct bytes. // Atom 00 00 has a very low quality, because it's only two bytes long and // both bytes are zeroes. Atom 01 01 01 01 is better but still not optimal, // because the same byte is repeated. Atom 01 02 03 04 is an optimal one. // // Args: // config: Pointer to YR_ATOMS_CONFIG struct. // atom: Pointer to YR_ATOM struct. // // Returns: // An integer indicating the atom's quality // int yr_atoms_heuristic_quality(YR_ATOMS_CONFIG* config, YR_ATOM* atom) { YR_BITMASK seen_bytes[YR_BITMASK_SIZE(256)]; int quality = 0; int unique_bytes = 0; assert(atom->length <= YR_MAX_ATOM_LENGTH); yr_bitmask_clear_all(seen_bytes); // Each byte in the atom contributes a certain amount of points to the // quality. Bytes [a-zA-Z] contribute 18 points each, common bytes like // 0x00, 0x20 and 0xFF contribute only 12 points, and the rest of the // bytes contribute 20 points. The ?? mask substracts 10 points, and masks // X? and ?X contribute 4 points. An additional boost consisting in 2x the // number of unique bytes in the atom is added to the quality. This are // some examples of the quality of atoms: // // 01 02 03 04 quality = 20 + 20 + 20 + 20 + 8 = 88 // 01 ?? 03 04 quality = 20 - 10 + 20 + 20 + 6 = 56 // 01 0? 03 quality = 20 + 4 + 20 + 4 = 48 // 01 02 quality = 20 + 20 + 4 = 44 // 01 ?? ?3 04 quality = 20 - 10 + 2 + 20 + 4 = 36 // 61 62 quality = 18 + 18 + 4 = 40 // 61 61 quality = 18 + 18 + 2 = 38 <- warning threshold // 00 01 quality = 12 + 20 + 4 = 36 // 01 ?? 02 quality = 20 - 10 + 20 + 4 = 34 // 01 quality = 20 + 1 = 21 for (int i = 0; i < atom->length; i++) { switch (atom->mask[i]) { case 0x00: quality -= 10; break; case 0x0F: quality += 4; break; case 0xF0: quality += 4; break; case 0xFF: switch (atom->bytes[i]) { case 0x00: case 0x20: case 0xCC: case 0xFF: // Common bytes contribute less to the quality than the rest. quality += 12; break; default: // Bytes in the a-z and A-Z ranges have a slightly lower quality // than the rest. We want to favor atoms that contain bytes outside // those ranges because they generate less additional atoms during // calls to _yr_atoms_case_combinations. if (yr_lowercase[atom->bytes[i]] >= 'a' && yr_lowercase[atom->bytes[i]] <= 'z') quality += 18; else quality += 20; } if (!yr_bitmask_is_set(seen_bytes, atom->bytes[i])) { yr_bitmask_set(seen_bytes, atom->bytes[i]); unique_bytes++; } } } // If all the bytes in the atom are equal and very common, let's penalize // it heavily. if (unique_bytes == 1 && (yr_bitmask_is_set(seen_bytes, 0x00) || yr_bitmask_is_set(seen_bytes, 0x20) || yr_bitmask_is_set(seen_bytes, 0x90) || yr_bitmask_is_set(seen_bytes, 0xCC) || yr_bitmask_is_set(seen_bytes, 0xFF))) { quality -= 10 * atom->length; } // In general atoms with more unique bytes have a better quality, so let's // boost the quality in the amount of unique bytes. else { quality += 2 * unique_bytes; } // The final quality is not zero-based, we start at YR_MAX_ATOM_QUALITY // for the best possible atom and substract from there. The best possible // quality is 21 * YR_MAX_ATOM_LENGTH (20 points per byte + 2 additional point // per unique byte, with a maximum of 2*YR_MAX_ATOM_LENGTH unique bytes). return YR_MAX_ATOM_QUALITY - 22 * YR_MAX_ATOM_LENGTH + quality; } //////////////////////////////////////////////////////////////////////////////// // Compares the byte sequence in a1 with the YR_ATOM in a2, taking atom's mask // into account. // // Returns: // < 0 if the first byte that does not match has a lower value in a1 than // in a2. // > 0 if the first byte that does not match has a greater value in a1 than // in a2. // = 0 if a1 is equal or matches a2. // static int _yr_atoms_cmp(const uint8_t* a1, YR_ATOM* a2) { int result = 0; int i = 0; while (result == 0 && i < a2->length) { switch (a2->mask[i]) { case 0xFF: case 0x0F: case 0xF0: case 0x00: result = (a1[i] & a2->mask[i]) - a2->bytes[i]; break; default: assert(false); } i++; } return result; } //////////////////////////////////////////////////////////////////////////////// // Returns a numeric value indicating the quality of an atom. The quality is // based in the atom quality table passed in "config". Very common atoms // (i.e: those with greater quality) have lower quality than those that are // uncommon. See the comment for yr_compiler_set_atom_quality_table for // details about the quality table's format. // // Args: // YR_ATOMS_CONFIG* config - Pointer to YR_ATOMS_CONFIG struct. // YR_ATOM* atom - Pointer to YR_ATOM struct. // // Returns: // An integer indicating the atom's quality // int yr_atoms_table_quality(YR_ATOMS_CONFIG* config, YR_ATOM* atom) { YR_ATOM_QUALITY_TABLE_ENTRY* table = config->quality_table; int begin = 0; int end = config->quality_table_entries; assert(atom->length <= YR_MAX_ATOM_LENGTH); while (end > begin) { int middle = begin + (end - begin) / 2; int c = _yr_atoms_cmp(table[middle].atom, atom); if (c < 0) { begin = middle + 1; } else if (c > 0) { end = middle; } else { int i = middle + 1; int quality = table[middle].quality; int min_quality = quality; while (i < end && _yr_atoms_cmp(table[i].atom, atom) == 0) { if (min_quality > table[i].quality) min_quality = table[i].quality; i++; } i = middle - 1; while (i >= begin && _yr_atoms_cmp(table[i].atom, atom) == 0) { if (min_quality > table[i].quality) min_quality = table[i].quality; i--; } return min_quality >> (YR_MAX_ATOM_LENGTH - atom->length); } } return YR_MAX_ATOM_QUALITY; } //////////////////////////////////////////////////////////////////////////////// // Returns the quality for the worst quality atom in a list. // int yr_atoms_min_quality(YR_ATOMS_CONFIG* config, YR_ATOM_LIST_ITEM* atom_list) { YR_ATOM_LIST_ITEM* atom; int quality; int min_quality = YR_MAX_ATOM_QUALITY; if (atom_list == NULL) return YR_MIN_ATOM_QUALITY; atom = atom_list; while (atom != NULL) { quality = config->get_atom_quality(config, &atom->atom); if (quality < min_quality) min_quality = quality; atom = atom->next; } return min_quality; } //////////////////////////////////////////////////////////////////////////////// // Creates a new node for an atoms tree. // static YR_ATOM_TREE_NODE* _yr_atoms_tree_node_create(uint8_t type) { YR_ATOM_TREE_NODE* new_node = (YR_ATOM_TREE_NODE*) yr_malloc( sizeof(YR_ATOM_TREE_NODE)); if (new_node != NULL) { new_node->type = type; new_node->atom.length = 0; new_node->next_sibling = NULL; new_node->children_head = NULL; new_node->children_tail = NULL; } return new_node; } //////////////////////////////////////////////////////////////////////////////// // Destroys a node from an atoms tree. // static void _yr_atoms_tree_node_destroy(YR_ATOM_TREE_NODE* node) { YR_ATOM_TREE_NODE* child; YR_ATOM_TREE_NODE* next_child; if (node == NULL) return; if (node->type == ATOM_TREE_OR || node->type == ATOM_TREE_AND) { child = node->children_head; while (child != NULL) { next_child = child->next_sibling; _yr_atoms_tree_node_destroy(child); child = next_child; } } yr_free(node); } //////////////////////////////////////////////////////////////////////////////// // Appends a new child node to another atoms tree node. // static void _yr_atoms_tree_node_append( YR_ATOM_TREE_NODE* dest, YR_ATOM_TREE_NODE* node) { if (dest->children_head == NULL) dest->children_head = node; if (dest->children_tail != NULL) dest->children_tail->next_sibling = node; dest->children_tail = node; } //////////////////////////////////////////////////////////////////////////////// // Destroys an atoms tree. // static void _yr_atoms_tree_destroy(YR_ATOM_TREE* atom_tree) { _yr_atoms_tree_node_destroy(atom_tree->root_node); yr_free(atom_tree); } //////////////////////////////////////////////////////////////////////////////// // Destroys an atoms list. // void yr_atoms_list_destroy(YR_ATOM_LIST_ITEM* list_head) { YR_ATOM_LIST_ITEM* item = list_head; YR_ATOM_LIST_ITEM* next; while (item != NULL) { next = item->next; yr_free(item); item = next; } } //////////////////////////////////////////////////////////////////////////////// // Concats two atoms lists. // static YR_ATOM_LIST_ITEM* _yr_atoms_list_concat( YR_ATOM_LIST_ITEM* list1, YR_ATOM_LIST_ITEM* list2) { YR_ATOM_LIST_ITEM* item; if (list1 == NULL) return list2; item = list1; while (item->next != NULL) { item = item->next; } item->next = list2; return list1; } //////////////////////////////////////////////////////////////////////////////// // If the atom starts or ends with an unknown byte (mask == 0x00), trim // those bytes out of the atom. We don't want to expand an atom like // { ?? 01 02 } into { 00 01 02 }, { 01 01 02}, { 02 01 02} .. { FF 01 02} // in those cases it's better to simply have a shorter atom { 01 02 }. // // Args: // atom: Pointer to the YR_ATOM to be trimmed. // // Returns: // The number of bytes that were trimmed from the beginning of the atom. // int _yr_atoms_trim(YR_ATOM* atom) { int mask_00 = 0; int mask_ff = 0; int trim_left = 0; while (trim_left < atom->length && atom->mask[trim_left] == 0) trim_left++; while (atom->length > trim_left && atom->mask[atom->length - 1] == 0) atom->length--; atom->length -= trim_left; if (atom->length == 0) return 0; // The trimmed atom goes from trim_left to trim_left + atom->length and the // first and last byte in the atom are known (mask == 0xFF). Now count the // number of known and unknown bytes in the atom (mask == 0xFF and // mask == 0x00 respectively). for (int i = 0; i < atom->length; i++) { if (atom->mask[trim_left + i] == 0xFF) mask_ff++; else if (atom->mask[trim_left + i] == 0x00) mask_00++; } // If the number of unknown bytes is >= than the number of known bytes // it doesn't make sense the to use this atom, so we use a single byte atom // containing the first known byte. If YR_MAX_ATOM_LENGTH == 4 this happens // only when the atom is like { XX ?? ?? YY }, so using the first known // byte is good enough. For larger values of YR_MAX_ATOM_LENGTH this is not // the most efficient solution, as better atoms could be choosen. For // example, in { XX ?? ?? ?? YY ZZ } the best atom is { YY ZZ } not { XX }. // But let's keep it like this for simplicity. if (mask_00 >= mask_ff) atom->length = 1; if (trim_left == 0) return 0; // Shift bytes and mask trim_left positions to the left. for (int i = 0; i < YR_MAX_ATOM_LENGTH - trim_left; i++) { atom->bytes[i] = atom->bytes[trim_left + i]; atom->mask[i] = atom->mask[trim_left + i]; } return trim_left; } //////////////////////////////////////////////////////////////////////////////// // This function receives an atom tree and returns a list of atoms to be added // to the Aho-Corasick automaton. // static int _yr_atoms_choose( YR_ATOMS_CONFIG* config, YR_ATOM_TREE_NODE* node, YR_ATOM_LIST_ITEM** chosen_atoms, int* atoms_quality) { YR_ATOM_TREE_NODE* child; YR_ATOM_LIST_ITEM* item; YR_ATOM_LIST_ITEM* tail; int shift, quality; int max_quality = YR_MIN_ATOM_QUALITY; int min_quality = YR_MAX_ATOM_QUALITY; *chosen_atoms = NULL; *atoms_quality = YR_MIN_ATOM_QUALITY; switch (node->type) { case ATOM_TREE_LEAF: item = (YR_ATOM_LIST_ITEM*) yr_malloc(sizeof(YR_ATOM_LIST_ITEM)); if (item == NULL) return ERROR_INSUFFICIENT_MEMORY; memcpy(&item->atom, &node->atom, sizeof(YR_ATOM)); shift = _yr_atoms_trim(&item->atom); if (item->atom.length > 0) { item->forward_code_ref = node->re_nodes[shift]->forward_code_ref; item->backward_code_ref = node->re_nodes[shift]->backward_code_ref; item->backtrack = 0; item->next = NULL; *chosen_atoms = item; *atoms_quality = config->get_atom_quality(config, &item->atom); } else { yr_free(item); } break; case ATOM_TREE_OR: // The choosen nodes are those coming from the highest quality child. child = node->children_head; while (child != NULL) { FAIL_ON_ERROR(_yr_atoms_choose(config, child, &item, &quality)); if (quality > max_quality) { max_quality = quality; yr_atoms_list_destroy(*chosen_atoms); *chosen_atoms = item; } else { yr_atoms_list_destroy(item); } if (max_quality == YR_MAX_ATOM_QUALITY) break; child = child->next_sibling; } *atoms_quality = max_quality; break; case ATOM_TREE_AND: // The choosen nodes are the concatenation of the the nodes choosen from // all the children. child = node->children_head; while (child != NULL) { FAIL_ON_ERROR(_yr_atoms_choose(config, child, &item, &quality)); if (quality < min_quality) min_quality = quality; if (item != NULL) { tail = item; while (tail->next != NULL) tail = tail->next; tail->next = *chosen_atoms; *chosen_atoms = item; } child = child->next_sibling; } *atoms_quality = min_quality; break; } return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Returns all combinations of lower and upper cases for a given atom. For // atom "abc" the output would be "abc" "abC" "aBC" and so on. Resulting // atoms are written into the output buffer in this format: // // [size of atom 1] [atom 1] ... [size of atom N] [atom N] [0] // // Notice the zero at the end to indicate where the output ends. // // The caller is responsible of providing a buffer large enough to hold the // returned atoms. // static uint8_t* _yr_atoms_case_combinations( uint8_t* atom, int atom_length, int atom_offset, uint8_t* output_buffer) { uint8_t c; uint8_t* new_atom; if (atom_offset + 1 < atom_length) output_buffer = _yr_atoms_case_combinations( atom, atom_length, atom_offset + 1, output_buffer); c = atom[atom_offset]; if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { // Write atom length. *output_buffer = atom_length; output_buffer++; memcpy(output_buffer, atom, atom_length); new_atom = output_buffer; output_buffer += atom_length; // Swap character case. if (c >= 'a' && c <= 'z') new_atom[atom_offset] -= 32; else new_atom[atom_offset] += 32; if (atom_offset + 1 < atom_length) output_buffer = _yr_atoms_case_combinations( new_atom, atom_length, atom_offset + 1, output_buffer); } if (atom_offset == 0) *output_buffer = 0; return output_buffer; } // Size of buffer used in _yr_atoms_case_insensitive for storing the all // the possible combinations for an atom. Each atom has up to YR_MAX_ATOM_LENGTH // characters and each character has two possible values (upper and lower case). // That means 2 ^ YR_MAX_ATOM_LENGTH combinations for an atom, where each atom // occupies YR_MAX_ATOM_LENGTH + 1 bytes (the atom itself +1 byte for its // length). One extra bytes is allocated for the zero value indicating the end. #define CASE_COMBINATIONS_BUFFER_SIZE \ (1 << YR_MAX_ATOM_LENGTH) * (YR_MAX_ATOM_LENGTH + 1) + 1 //////////////////////////////////////////////////////////////////////////////// // For a given list of atoms returns another list of atoms // with every case combination. // static int _yr_atoms_case_insensitive( YR_ATOM_LIST_ITEM* atoms, YR_ATOM_LIST_ITEM** case_insensitive_atoms) { YR_ATOM_LIST_ITEM* atom; YR_ATOM_LIST_ITEM* new_atom; uint8_t buffer[CASE_COMBINATIONS_BUFFER_SIZE]; uint8_t atom_length; uint8_t* atoms_cursor; int i; *case_insensitive_atoms = NULL; atom = atoms; while (atom != NULL) { _yr_atoms_case_combinations(atom->atom.bytes, atom->atom.length, 0, buffer); atoms_cursor = buffer; atom_length = *atoms_cursor; atoms_cursor++; while (atom_length != 0) { new_atom = (YR_ATOM_LIST_ITEM*) yr_malloc(sizeof(YR_ATOM_LIST_ITEM)); if (new_atom == NULL) return ERROR_INSUFFICIENT_MEMORY; for (i = 0; i < atom_length; i++) { new_atom->atom.bytes[i] = atoms_cursor[i]; new_atom->atom.mask[i] = 0xFF; } new_atom->atom.length = atom_length; new_atom->forward_code_ref = atom->forward_code_ref; new_atom->backward_code_ref = atom->backward_code_ref; new_atom->backtrack = atom->backtrack; new_atom->next = *case_insensitive_atoms; *case_insensitive_atoms = new_atom; atoms_cursor += atom_length; atom_length = *atoms_cursor; atoms_cursor++; } atom = atom->next; } return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // For a given list of atoms returns another list after a single byte xor // has been applied to it. // static int _yr_atoms_xor( YR_ATOM_LIST_ITEM* atoms, uint8_t min, uint8_t max, YR_ATOM_LIST_ITEM** xor_atoms) { YR_ATOM_LIST_ITEM* atom; YR_ATOM_LIST_ITEM* new_atom; int i, j; *xor_atoms = NULL; atom = atoms; while (atom != NULL) { for (j = min; j <= max; j++) { new_atom = (YR_ATOM_LIST_ITEM*) yr_malloc(sizeof(YR_ATOM_LIST_ITEM)); if (new_atom == NULL) return ERROR_INSUFFICIENT_MEMORY; for (i = 0; i < atom->atom.length; i++) { new_atom->atom.bytes[i] = atom->atom.bytes[i] ^ j; new_atom->atom.mask[i] = 0xFF; } new_atom->atom.length = yr_min(atom->atom.length, YR_MAX_ATOM_LENGTH); new_atom->forward_code_ref = atom->forward_code_ref; new_atom->backward_code_ref = atom->backward_code_ref; new_atom->backtrack = atom->backtrack; new_atom->next = *xor_atoms; *xor_atoms = new_atom; } atom = atom->next; } return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // For a given list of atoms returns another list with the corresponding // wide atoms. Wide atoms are just the original atoms with interleaved zeroes, // for example: 01 02 -> 01 00 02 00 // static int _yr_atoms_wide( YR_ATOM_LIST_ITEM* atoms, YR_ATOM_LIST_ITEM** wide_atoms) { YR_ATOM_LIST_ITEM* atom; YR_ATOM_LIST_ITEM* new_atom; int i; *wide_atoms = NULL; atom = atoms; while (atom != NULL) { new_atom = (YR_ATOM_LIST_ITEM*) yr_malloc(sizeof(YR_ATOM_LIST_ITEM)); if (new_atom == NULL) return ERROR_INSUFFICIENT_MEMORY; for (i = 0; i < YR_MAX_ATOM_LENGTH; i++) { new_atom->atom.bytes[i] = 0; new_atom->atom.mask[i] = 0xFF; } for (i = 0; i < atom->atom.length; i++) { if (i * 2 < YR_MAX_ATOM_LENGTH) new_atom->atom.bytes[i * 2] = atom->atom.bytes[i]; else break; } new_atom->atom.length = yr_min(atom->atom.length * 2, YR_MAX_ATOM_LENGTH); new_atom->forward_code_ref = atom->forward_code_ref; new_atom->backward_code_ref = atom->backward_code_ref; new_atom->backtrack = atom->backtrack * 2; new_atom->next = *wide_atoms; *wide_atoms = new_atom; atom = atom->next; } return ERROR_SUCCESS; } struct STACK_ITEM { RE_NODE* re_node; YR_ATOM_TREE_NODE* new_appending_node; }; #define make_atom_from_re_nodes(atom, nodes_length, nodes) \ { \ atom.length = nodes_length; \ for (i = 0; i < atom.length; i++) \ { \ atom.bytes[i] = (uint8_t) (recent_re_nodes)[i]->value; \ atom.mask[i] = (uint8_t) (recent_re_nodes)[i]->mask; \ } \ } //////////////////////////////////////////////////////////////////////////////// // Extract atoms from a regular expression. This is a helper function used by // yr_atoms_extract_from_re that receives the abstract syntax tree for a regexp // (or hex pattern) and builds an atom tree. The appending_node argument is a // pointer to the ATOM_TREE_OR node at the root of the atom tree. This function // creates the tree by appending new nodes to it. // static int _yr_atoms_extract_from_re( YR_ATOMS_CONFIG* config, RE_AST* re_ast, YR_ATOM_TREE_NODE* appending_node) { YR_STACK* stack; RE_NODE* re_node; YR_ATOM atom = {0}; YR_ATOM best_atom = {0}; struct STACK_ITEM si; int i, shift; int quality; int best_quality = -1; int n = 0; YR_ATOM_TREE_NODE* and_node; YR_ATOM_TREE_NODE* left_node; YR_ATOM_TREE_NODE* right_node; // The RE_NODEs most recently visited that can conform an atom (ie: // RE_NODE_LITERAL, RE_NODE_MASKED_LITERAL and RE_NODE_ANY). The number of // items in this array is n. RE_NODE* recent_re_nodes[YR_MAX_ATOM_LENGTH]; // The RE_NODEs corresponding to the best atom found so far for the current // appending node. RE_NODE* best_atom_re_nodes[YR_MAX_ATOM_LENGTH]; // This holds the ATOM_TREE_OR node where leaves (ATOM_TREE_LEAF) are // currently being appended. YR_ATOM_TREE_NODE* current_appending_node = NULL; // This holds the ATOM_TREE_LEAF node whose atom is currently being updated. YR_ATOM_TREE_NODE* leaf = NULL; FAIL_ON_ERROR(yr_stack_create(1024, sizeof(si), &stack)); // This first item pushed in the stack is the last one to be poped out, the // sole purpose of this item is forcing that any pending leaf is appended to // appending_node during the last iteration of the loop. si.re_node = NULL; si.new_appending_node = appending_node; FAIL_ON_ERROR_WITH_CLEANUP( yr_stack_push(stack, (void*) &si), yr_stack_destroy(stack)); // Start processing the root node. si.re_node = re_ast->root_node; // Leaf nodes are initially appended to the node passed in the appending_node, // argument which is the root ATOM_TREE_OR node that is empty at this point. si.new_appending_node = appending_node; FAIL_ON_ERROR_WITH_CLEANUP( yr_stack_push(stack, (void*) &si), yr_stack_destroy(stack)); while (yr_stack_pop(stack, (void*) &si)) { // Change the appending node if the item poped from the stack says so. if (si.new_appending_node != NULL) { // Before changing the appending node let's append any pending leaf to // the current appending node. if (n > 0) { make_atom_from_re_nodes(atom, n, recent_re_nodes); shift = _yr_atoms_trim(&atom); quality = config->get_atom_quality(config, &atom); FAIL_ON_NULL_WITH_CLEANUP( leaf = _yr_atoms_tree_node_create(ATOM_TREE_LEAF), yr_stack_destroy(stack)); if (quality > best_quality) { memcpy(&leaf->atom, &atom, sizeof(atom)); memcpy( &leaf->re_nodes, &recent_re_nodes[shift], sizeof(recent_re_nodes) - shift * sizeof(recent_re_nodes[0])); } else { memcpy(&leaf->atom, &best_atom, sizeof(best_atom)); memcpy( &leaf->re_nodes, &best_atom_re_nodes, sizeof(best_atom_re_nodes)); } _yr_atoms_tree_node_append(current_appending_node, leaf); n = 0; } current_appending_node = si.new_appending_node; best_quality = -1; } if (si.re_node != NULL) { switch (si.re_node->type) { case RE_NODE_LITERAL: case RE_NODE_MASKED_LITERAL: case RE_NODE_ANY: if (n < YR_MAX_ATOM_LENGTH) { recent_re_nodes[n] = si.re_node; best_atom_re_nodes[n] = si.re_node; best_atom.bytes[n] = (uint8_t) si.re_node->value; best_atom.mask[n] = (uint8_t) si.re_node->mask; best_atom.length = ++n; } else if (best_quality < YR_MAX_ATOM_QUALITY) { make_atom_from_re_nodes(atom, n, recent_re_nodes); shift = _yr_atoms_trim(&atom); quality = config->get_atom_quality(config, &atom); if (quality > best_quality) { for (i = 0; i < atom.length; i++) { best_atom.bytes[i] = atom.bytes[i]; best_atom.mask[i] = atom.mask[i]; best_atom_re_nodes[i] = recent_re_nodes[i + shift]; } best_atom.length = atom.length; best_quality = quality; } for (i = 1; i < YR_MAX_ATOM_LENGTH; i++) recent_re_nodes[i - 1] = recent_re_nodes[i]; recent_re_nodes[YR_MAX_ATOM_LENGTH - 1] = si.re_node; } break; case RE_NODE_CONCAT: re_node = si.re_node->children_tail; // Push children right to left, they are poped left to right. while (re_node != NULL) { si.new_appending_node = NULL; si.re_node = re_node; FAIL_ON_ERROR_WITH_CLEANUP( yr_stack_push(stack, &si), yr_stack_destroy(stack)); re_node = re_node->prev_sibling; } break; case RE_NODE_ALT: // Create ATOM_TREE_AND node with two ATOM_TREE_OR children nodes. and_node = _yr_atoms_tree_node_create(ATOM_TREE_AND); left_node = _yr_atoms_tree_node_create(ATOM_TREE_OR); right_node = _yr_atoms_tree_node_create(ATOM_TREE_OR); if (and_node == NULL || left_node == NULL || right_node == NULL) { _yr_atoms_tree_node_destroy(and_node); _yr_atoms_tree_node_destroy(left_node); _yr_atoms_tree_node_destroy(right_node); yr_stack_destroy(stack); return ERROR_INSUFFICIENT_MEMORY; } and_node->children_head = left_node; and_node->children_tail = right_node; left_node->next_sibling = right_node; // Add the ATOM_TREE_AND as children of the current node. _yr_atoms_tree_node_append(current_appending_node, and_node); re_node = si.re_node; si.new_appending_node = current_appending_node; si.re_node = NULL; FAIL_ON_ERROR_WITH_CLEANUP( yr_stack_push(stack, &si), yr_stack_destroy(stack)); // RE_NODE_ALT nodes has only two children, so children_head is the // left one, and children_tail is right one. si.new_appending_node = right_node; si.re_node = re_node->children_tail; FAIL_ON_ERROR_WITH_CLEANUP( yr_stack_push(stack, &si), yr_stack_destroy(stack)); si.new_appending_node = left_node; si.re_node = re_node->children_head; FAIL_ON_ERROR_WITH_CLEANUP( yr_stack_push(stack, &si), yr_stack_destroy(stack)); break; case RE_NODE_PLUS: re_node = si.re_node; si.new_appending_node = current_appending_node; si.re_node = NULL; FAIL_ON_ERROR_WITH_CLEANUP( yr_stack_push(stack, &si), yr_stack_destroy(stack)); si.new_appending_node = NULL; // RE_NODE_PLUS nodes has a single child, which is children_head. si.re_node = re_node->children_head; FAIL_ON_ERROR_WITH_CLEANUP( yr_stack_push(stack, &si), yr_stack_destroy(stack)); break; case RE_NODE_RANGE: re_node = si.re_node; si.new_appending_node = current_appending_node; si.re_node = NULL; FAIL_ON_ERROR_WITH_CLEANUP( yr_stack_push(stack, &si), yr_stack_destroy(stack)); si.new_appending_node = NULL; // RE_NODE_RANGE nodes has a single child, which is children_head. si.re_node = re_node->children_head; // In a regexp like /a{10,20}/ the optimal atom is 'aaaa' (assuming // that YR_MAX_ATOM_LENGTH = 4) because the 'a' character must appear // at least 10 times in the matching string. Each call in the loop // will append one 'a' to the atom, so YR_MAX_ATOM_LENGTH iterations // are enough. for (i = 0; i < yr_min(re_node->start, YR_MAX_ATOM_LENGTH); i++) { FAIL_ON_ERROR_WITH_CLEANUP( yr_stack_push(stack, &si), yr_stack_destroy(stack)); } break; case RE_NODE_RANGE_ANY: case RE_NODE_STAR: case RE_NODE_CLASS: case RE_NODE_WORD_CHAR: case RE_NODE_NON_WORD_CHAR: case RE_NODE_SPACE: case RE_NODE_NON_SPACE: case RE_NODE_DIGIT: case RE_NODE_NON_DIGIT: case RE_NODE_EMPTY: case RE_NODE_ANCHOR_START: case RE_NODE_ANCHOR_END: case RE_NODE_WORD_BOUNDARY: case RE_NODE_NON_WORD_BOUNDARY: case RE_NODE_NOT_LITERAL: case RE_NODE_MASKED_NOT_LITERAL: si.new_appending_node = current_appending_node; si.re_node = NULL; FAIL_ON_ERROR_WITH_CLEANUP( yr_stack_push(stack, &si), yr_stack_destroy(stack)); break; default: assert(false); } } } yr_stack_destroy(stack); return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Makes an exact copy of an YR_ATOM_LIST_ITEM. // static YR_ATOM_LIST_ITEM* _yr_atoms_clone_list_item(YR_ATOM_LIST_ITEM* item) { YR_ATOM_LIST_ITEM* clone = (YR_ATOM_LIST_ITEM*) yr_malloc( sizeof(YR_ATOM_LIST_ITEM)); if (clone == NULL) return NULL; memcpy(clone, item, sizeof(YR_ATOM_LIST_ITEM)); return clone; } //////////////////////////////////////////////////////////////////////////////// // Given list of atoms that may contain wildcards, replace those wildcarded // atoms with a list of non-wildcarded atoms covering all the combinations // allowed by the wildcarded atom. For example, the atom {01 ?2 03} will be // replaced by {01 02 03}, {01 12 03}, {01 22 03} .. {01 F2 03}. The list // is modified in-place. // // Args: // atoms: Pointer to first element of the list. // // Returns: // ERROR_SUCCESS or ERROR_INSUFFICIENT_MEMORY. // static int _yr_atoms_expand_wildcards(YR_ATOM_LIST_ITEM* atoms) { int i; YR_ATOM_LIST_ITEM* atom = atoms; YR_ATOM_LIST_ITEM* new_atom; YR_ATOM_LIST_ITEM* prev_atom; YR_ATOM_LIST_ITEM* next_atom; while (atom != NULL) { bool expanded = false; for (i = 0; i < atom->atom.length; i++) { uint16_t a, s, e, incr = 1; switch (atom->atom.mask[i]) { case 0x00: expanded = true; s = 0x00; e = 0xFF; break; case 0x0F: expanded = true; s = atom->atom.bytes[i]; e = atom->atom.bytes[i] | 0xF0; incr = 0x10; break; case 0xF0: expanded = true; s = atom->atom.bytes[i]; e = atom->atom.bytes[i] | 0x0F; break; default: s = 0; e = 0; } if (s != e) { atom->atom.bytes[i] = (uint8_t) s; atom->atom.mask[i] = 0xFF; } prev_atom = atom; next_atom = atom->next; for (a = s + incr; a <= e; a += incr) { new_atom = _yr_atoms_clone_list_item(atom); if (new_atom == NULL) return ERROR_INSUFFICIENT_MEMORY; new_atom->atom.bytes[i] = (uint8_t) a; new_atom->atom.mask[i] = 0xFF; new_atom->next = next_atom; prev_atom->next = new_atom; prev_atom = new_atom; } } if (!expanded) atom = atom->next; } return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Extract atoms from a regular expression. This function receives the abstract // syntax tree for a regexp (or hex pattern) and returns a list of atoms that // should be added to the Aho-Corasick automaton. // int yr_atoms_extract_from_re( YR_ATOMS_CONFIG* config, RE_AST* re_ast, YR_MODIFIER modifier, YR_ATOM_LIST_ITEM** atoms, int* min_atom_quality) { YR_ATOM_TREE* atom_tree = (YR_ATOM_TREE*) yr_malloc(sizeof(YR_ATOM_TREE)); YR_ATOM_LIST_ITEM* wide_atoms; YR_ATOM_LIST_ITEM* case_insensitive_atoms; if (atom_tree == NULL) return ERROR_INSUFFICIENT_MEMORY; atom_tree->root_node = _yr_atoms_tree_node_create(ATOM_TREE_OR); if (atom_tree->root_node == NULL) { _yr_atoms_tree_destroy(atom_tree); return ERROR_INSUFFICIENT_MEMORY; } FAIL_ON_ERROR_WITH_CLEANUP( _yr_atoms_extract_from_re(config, re_ast, atom_tree->root_node), _yr_atoms_tree_destroy(atom_tree)); // Initialize atom list *atoms = NULL; // Choose the atoms that will be used. FAIL_ON_ERROR_WITH_CLEANUP( _yr_atoms_choose(config, atom_tree->root_node, atoms, min_atom_quality), _yr_atoms_tree_destroy(atom_tree)); _yr_atoms_tree_destroy(atom_tree); FAIL_ON_ERROR_WITH_CLEANUP( _yr_atoms_expand_wildcards(*atoms), { // Cleanup yr_atoms_list_destroy(*atoms); *atoms = NULL; }); // Don't do convert atoms to wide here if either base64 modifier is used. // This is to avoid the situation where we have "base64 wide" because // the wide has already been applied BEFORE the base64 encoding. if (modifier.flags & STRING_FLAGS_WIDE && !(modifier.flags & STRING_FLAGS_BASE64 || modifier.flags & STRING_FLAGS_BASE64_WIDE)) { FAIL_ON_ERROR_WITH_CLEANUP( _yr_atoms_wide(*atoms, &wide_atoms), { // Cleanup yr_atoms_list_destroy(*atoms); yr_atoms_list_destroy(wide_atoms); *atoms = NULL; }); if (modifier.flags & STRING_FLAGS_ASCII) { *atoms = _yr_atoms_list_concat(*atoms, wide_atoms); } else { yr_atoms_list_destroy(*atoms); *atoms = wide_atoms; } } if (modifier.flags & STRING_FLAGS_NO_CASE) { FAIL_ON_ERROR_WITH_CLEANUP( _yr_atoms_case_insensitive(*atoms, &case_insensitive_atoms), { // Cleanup yr_atoms_list_destroy(*atoms); yr_atoms_list_destroy(case_insensitive_atoms); *atoms = NULL; }); *atoms = _yr_atoms_list_concat(*atoms, case_insensitive_atoms); } return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Extract atoms from a string. // int yr_atoms_extract_from_string( YR_ATOMS_CONFIG* config, uint8_t* string, int32_t string_length, YR_MODIFIER modifier, YR_ATOM_LIST_ITEM** atoms, int* min_atom_quality) { YR_ATOM_LIST_ITEM* item; YR_ATOM_LIST_ITEM* case_insensitive_atoms; YR_ATOM_LIST_ITEM* xor_atoms; YR_ATOM_LIST_ITEM* wide_atoms; YR_ATOM atom; int quality, max_quality; int i; item = (YR_ATOM_LIST_ITEM*) yr_malloc(sizeof(YR_ATOM_LIST_ITEM)); if (item == NULL) return ERROR_INSUFFICIENT_MEMORY; item->forward_code_ref = YR_ARENA_NULL_REF; item->backward_code_ref = YR_ARENA_NULL_REF; item->next = NULL; item->backtrack = 0; item->atom.length = yr_min(string_length, YR_MAX_ATOM_LENGTH); for (i = 0; i < item->atom.length; i++) { item->atom.bytes[i] = string[i]; item->atom.mask[i] = 0xFF; } max_quality = config->get_atom_quality(config, &item->atom); atom.length = YR_MAX_ATOM_LENGTH; memset(atom.mask, 0xFF, atom.length); for (i = YR_MAX_ATOM_LENGTH; i < string_length && max_quality < YR_MAX_ATOM_QUALITY; i++) { atom.length = YR_MAX_ATOM_LENGTH; memcpy(atom.bytes, string + i - YR_MAX_ATOM_LENGTH + 1, atom.length); quality = config->get_atom_quality(config, &atom); if (quality > max_quality) { memcpy(&item->atom, &atom, sizeof(atom)); item->backtrack = i - YR_MAX_ATOM_LENGTH + 1; max_quality = quality; } } *atoms = item; *min_atom_quality = max_quality; if (modifier.flags & STRING_FLAGS_WIDE) { FAIL_ON_ERROR_WITH_CLEANUP( _yr_atoms_wide(*atoms, &wide_atoms), { // Cleanup yr_atoms_list_destroy(*atoms); yr_atoms_list_destroy(wide_atoms); *atoms = NULL; }); if (modifier.flags & STRING_FLAGS_ASCII) { *atoms = _yr_atoms_list_concat(*atoms, wide_atoms); } else { yr_atoms_list_destroy(*atoms); *atoms = wide_atoms; } } if (modifier.flags & STRING_FLAGS_NO_CASE) { FAIL_ON_ERROR_WITH_CLEANUP( _yr_atoms_case_insensitive(*atoms, &case_insensitive_atoms), { // Cleanup yr_atoms_list_destroy(*atoms); yr_atoms_list_destroy(case_insensitive_atoms); *atoms = NULL; }); *atoms = _yr_atoms_list_concat(*atoms, case_insensitive_atoms); } if (modifier.flags & STRING_FLAGS_XOR) { FAIL_ON_ERROR_WITH_CLEANUP( _yr_atoms_xor(*atoms, modifier.xor_min, modifier.xor_max, &xor_atoms), { // Cleanup yr_atoms_list_destroy(*atoms); yr_atoms_list_destroy(xor_atoms); *atoms = NULL; }); yr_atoms_list_destroy(*atoms); *atoms = xor_atoms; } // Recheck the atom quality, in case we have just generated some poor atoms. // https://github.com/VirusTotal/yara/issues/1172 for (item = *atoms; item != NULL; item = item->next) { quality = config->get_atom_quality(config, &item->atom); if (quality < *min_atom_quality) *min_atom_quality = quality; } return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Prints an atom tree node. Used only for debugging purposes. // void yr_atoms_tree_node_print(YR_ATOM_TREE_NODE* node) { YR_ATOM_TREE_NODE* child; if (node == NULL) { printf("Empty tree node\n"); return; } switch (node->type) { case ATOM_TREE_LEAF: for (int i = 0; i < node->atom.length; i++) printf("%02X", node->atom.bytes[i]); break; case ATOM_TREE_AND: case ATOM_TREE_OR: if (node->type == ATOM_TREE_AND) printf("AND"); else printf("OR"); printf("("); child = node->children_head; while (child != NULL) { yr_atoms_tree_node_print(child); child = child->next_sibling; if (child != NULL) printf(","); } printf(")"); break; } } yara-4.5.3/libyara/base64.c000066400000000000000000000317241501365277300153520ustar00rootroot00000000000000/* Copyright (c) 2020. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include //////////////////////////////////////////////////////////////////////////////// // Given a pointer to a SIZED_STRING append 0, 1 or 2 bytes and base64 encode // the string. The number of padding bytes is returned in "pad" and the caller // is expected to trim the appropriate number of leading and trailing bytes. // // This is based upon the ideas at: // https://www.leeholmes.com/searching-for-content-in-base-64-strings/ // // The caller is responsible for freeing the returned string. // static SIZED_STRING* _yr_modified_base64_encode( SIZED_STRING* in, SIZED_STRING* alphabet, int i, int* pad) { uint8_t* src = (uint8_t*) in->c_string; size_t len = in->length; SIZED_STRING* out; uint8_t* p; uint8_t* end; char* alphabet_str = alphabet->c_string; uint8_t* tmp; int j; *pad = ((i + len) % 3) ? 3 - ((i + len) % 3) : 0; // Add "i" for the number of prepended bytes. out = (SIZED_STRING*) yr_malloc( sizeof(SIZED_STRING) + i + ((len * 4 + 3) / 3) + *pad); if (out == NULL) return NULL; tmp = (uint8_t*) yr_malloc(sizeof(uint8_t) * (len + i)); if (tmp == NULL) { yr_free(out); return NULL; } // Prepend appropriate number of bytes and copy remaining input bytes into // temporary buffer. for (j = 0; j < i; j++) tmp[j] = 'A'; memcpy(tmp + j, src, len); src = tmp; p = (uint8_t*) out->c_string; end = src + len + j; while (end - src >= 3) { *p++ = alphabet_str[src[0] >> 2]; *p++ = alphabet_str[((src[0] & 0x03) << 4 | src[1] >> 4)]; *p++ = alphabet_str[((src[1] & 0x0f) << 2 | (src[2] >> 6))]; *p++ = alphabet_str[src[2] & 0x3f]; src += 3; } // Handle remaining bytes and padding. if (end - src) { *p++ = alphabet_str[src[0] >> 2]; if (end - src == 1) { *p++ = alphabet_str[(src[0] & 0x03) << 4]; *p++ = '='; } else { *p++ = alphabet_str[((src[0] & 0x03) << 4 | src[1] >> 4)]; *p++ = alphabet_str[(src[1] & 0x0f) << 2]; } *p++ = '='; } yr_free(tmp); out->length = (uint32_t)(p - (uint8_t*) out->c_string); return out; } //////////////////////////////////////////////////////////////////////////////// // Given a base64 encoded string, return a new string with leading and trailing // bytes stripped appropriately. The number of leading bytes to skip is always // (i + 1) or zero when no leading bytes are added and the number of trailing // bytes is always (pad + 1) or zero when pad is zero. Also, convert the final // string to wide if desired. // // Note: This implementation assumes you only prepend 0, 1 or 2 bytes. // static SIZED_STRING* _yr_base64_get_base64_substring( SIZED_STRING* encoded_str, int wide, int i, int pad) { SIZED_STRING* new_str; SIZED_STRING* final_str; char* start; uint32_t length; int trailing; int leading; trailing = pad ? pad + 1 : 0; leading = i ? i + 1 : 0; length = encoded_str->length - (leading + trailing); new_str = (SIZED_STRING*) yr_malloc(sizeof(SIZED_STRING) + length); if (new_str == NULL) return NULL; start = encoded_str->c_string + leading; memcpy(new_str->c_string, start, length); new_str->length = length; new_str->c_string[length] = '\0'; if (wide) { final_str = ss_convert_to_wide(new_str); yr_free(new_str); } else { final_str = new_str; } return final_str; } // RE metacharacters which need to be escaped when generating the final RE. #define IS_METACHAR(x) \ (x == '\\' || x == '^' || x == '$' || x == '|' || x == '(' || x == ')' || \ x == '[' || x == ']' || x == '*' || x == '?' || x == '{' || x == ',' || \ x == '.' || x == '+' || x == '}') //////////////////////////////////////////////////////////////////////////////// // Given a SIZED_STRING return the number of characters which will need to be // escaped when generating the final string to pass to the regexp compiler. // static int _yr_base64_count_escaped(SIZED_STRING* str) { int c = 0; for (uint32_t i = 0; i < str->length; i++) { // We must be careful to escape null bytes because they break the RE lexer. if (IS_METACHAR(str->c_string[i])) c++; else if (str->c_string[i] == '\x00') c += 4; } return c; } //////////////////////////////////////////////////////////////////////////////// // Create nodes representing the different encodings of a base64 string. // static int _yr_base64_create_nodes( SIZED_STRING* str, SIZED_STRING* alphabet, int wide, BASE64_NODE** head, BASE64_NODE** tail) { SIZED_STRING* encoded_str; SIZED_STRING* final_str; BASE64_NODE* node; int pad; for (int i = 0; i <= 2; i++) { if (i == 1 && str->length == 1) continue; node = (BASE64_NODE*) yr_malloc(sizeof(BASE64_NODE)); if (node == NULL) return ERROR_INSUFFICIENT_MEMORY; FAIL_ON_NULL_WITH_CLEANUP( encoded_str = _yr_modified_base64_encode(str, alphabet, i, &pad), yr_free(node)); // Now take the encoded string and strip the bytes which are affected by // the leading and trailing bytes of the plaintext. FAIL_ON_NULL_WITH_CLEANUP( final_str = _yr_base64_get_base64_substring(encoded_str, wide, i, pad), { yr_free(encoded_str); yr_free(node); }); yr_free(encoded_str); node->str = final_str; node->escaped = _yr_base64_count_escaped(node->str); node->next = NULL; if (*head == NULL) *head = node; if (*tail == NULL) { *tail = node; } else { (*tail)->next = node; *tail = node; } } return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Useful for printing the encoded strings. // void _yr_base64_print_nodes(BASE64_NODE* head) { BASE64_NODE* p = head; while (p != NULL) { for (size_t i = 0; i < p->str->length; i++) { if (p->str->c_string[i] >= 32 && p->str->c_string[i] <= 126) printf("%c", p->str->c_string[i]); else printf("\\x%02x", p->str->c_string[i]); } printf("\n"); p = p->next; } } //////////////////////////////////////////////////////////////////////////////// // Destroy a list of base64 nodes. // static void _yr_base64_destroy_nodes(BASE64_NODE* head) { BASE64_NODE* p = head; BASE64_NODE* next; while (p != NULL) { yr_free(p->str); next = p->next; yr_free(p); p = next; } } //////////////////////////////////////////////////////////////////////////////// // Create the regexp that is the alternatives of each of the strings collected // in the BASE64_NODE list. // int _yr_base64_create_regexp( BASE64_NODE* head, RE_AST** re_ast, RE_ERROR* re_error) { BASE64_NODE* p = head; char* re_str; char* s; uint32_t length = 0; // The number of nodes in the list, used to know how many '|'. uint32_t c = 0; while (p != NULL) { length += (p->str->length + p->escaped); c++; p = p->next; } if (c == 0) return ERROR_INSUFFICIENT_MEMORY; // Make sure to include '(' and ')'. // The number of '|' is number of nodes - 1. re_str = (char*) yr_malloc(length + 2 + (c - 1) + 1); if (re_str == NULL) return ERROR_INSUFFICIENT_MEMORY; s = re_str; p = head; *s++ = '('; while (p != NULL) { for (uint32_t i = 0; i < p->str->length; i++) { if (IS_METACHAR(p->str->c_string[i])) *s++ = '\\'; if (p->str->c_string[i] == '\x00') { *s++ = '\\'; *s++ = 'x'; *s++ = '0'; *s++ = '0'; } else *s++ = p->str->c_string[i]; } if (p->next != NULL) *s++ = '|'; p = p->next; } *s++ = ')'; *s = '\x00'; // Useful for debugging as long as the string has no NULL bytes in it. ;) // printf("%s\n", re_str); FAIL_ON_ERROR_WITH_CLEANUP( yr_re_parse(re_str, re_ast, re_error, RE_PARSER_FLAG_NONE), yr_free(re_str)); yr_free(re_str); return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Given a string and an alphabet, generate the RE_AST suitable for representing // the different encodings of the string. This means we generate // "(ABCD|EFGH|IJKL)" and must be careful to escape any special characters as // a result of the base64 encoding. // // This uses ideas from: // https://www.leeholmes.com/searching-for-content-in-base-64-strings/ // // This does not emit the code for the RE. A further call to yr_re_ast_emit_code // is required to get the code. // int yr_base64_ast_from_string( SIZED_STRING* in_str, YR_MODIFIER modifier, RE_AST** re_ast, RE_ERROR* error) { BASE64_NODE* head = NULL; BASE64_NODE* tail = NULL; SIZED_STRING* wide_str; if (modifier.flags & STRING_FLAGS_WIDE) { wide_str = ss_convert_to_wide(in_str); if (modifier.flags & STRING_FLAGS_BASE64) { FAIL_ON_ERROR_WITH_CLEANUP( _yr_base64_create_nodes(wide_str, modifier.alphabet, 0, &head, &tail), { // Cleanup strcpy(error->message, "Failure encoding base64 wide string"); yr_free(wide_str); _yr_base64_destroy_nodes(head); }); } if (modifier.flags & STRING_FLAGS_BASE64_WIDE) { FAIL_ON_ERROR_WITH_CLEANUP( _yr_base64_create_nodes(wide_str, modifier.alphabet, 1, &head, &tail), { // Cleanup strcpy(error->message, "Failure encoding base64wide wide string"); yr_free(wide_str); _yr_base64_destroy_nodes(head); }); } yr_free(wide_str); } if (modifier.flags & STRING_FLAGS_ASCII) { if (modifier.flags & STRING_FLAGS_BASE64) { FAIL_ON_ERROR_WITH_CLEANUP( _yr_base64_create_nodes(in_str, modifier.alphabet, 0, &head, &tail), { // Cleanup strcpy(error->message, "Failure encoding base64 ascii string"); _yr_base64_destroy_nodes(head); }); } if (modifier.flags & STRING_FLAGS_BASE64_WIDE) { FAIL_ON_ERROR_WITH_CLEANUP( _yr_base64_create_nodes(in_str, modifier.alphabet, 1, &head, &tail), { // Cleanup strcpy(error->message, "Failure encoding base64wide ascii string"); _yr_base64_destroy_nodes(head); }); } } if (!(modifier.flags & STRING_FLAGS_WIDE) && !(modifier.flags & STRING_FLAGS_ASCII)) { if (modifier.flags & STRING_FLAGS_BASE64) { FAIL_ON_ERROR_WITH_CLEANUP( _yr_base64_create_nodes(in_str, modifier.alphabet, 0, &head, &tail), { // Cleanup strcpy(error->message, "Failure encoding base64 string"); _yr_base64_destroy_nodes(head); }); } if (modifier.flags & STRING_FLAGS_BASE64_WIDE) { FAIL_ON_ERROR_WITH_CLEANUP( _yr_base64_create_nodes(in_str, modifier.alphabet, 1, &head, &tail), { // Cleanup strcpy(error->message, "Failure encoding base64wide string"); _yr_base64_destroy_nodes(head); }); } } // Useful for printing the contents of the nodes, to make sure they were // encoded and stripped properly. //_yr_base64_print_nodes(head); // Create the final regex string to be parsed from all the nodes. // Error message is filled in by the caller in case of failure. FAIL_ON_ERROR_WITH_CLEANUP( _yr_base64_create_regexp(head, re_ast, error), _yr_base64_destroy_nodes(head)); _yr_base64_destroy_nodes(head); return ERROR_SUCCESS; } yara-4.5.3/libyara/bitmask.c000066400000000000000000000100061501365277300157060ustar00rootroot00000000000000/* Copyright (c) 2018. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include //////////////////////////////////////////////////////////////////////////////// // Find the smallest offset within bitmask A where bitmask B can be accommodated // without bit collisions. A collision occurs when both bitmasks have a bit set // to 1 at the same offset. This function assumes that the first bit in B is 1 // and do optimizations that rely on that. // // The function also receives a pointer to an uint32_t where the function stores // a value that is used for speeding-up subsequent searches over the same // bitmask A. When called for the first time with some bitmask A, the pointer // must point to a zero-initialized uint32_t. In the next call the function uses // the previously stored value for skipping over a portion of the A bitmask and // updates the value. // // Args: // a: Bitmask A // b: Bitmask B // len_a: Length of bitmask A in bits // len_b: Length of bitmask B in bits // off_a: Address of an uint32_t indicating the offset within bitmask A where // to start searching. In the first call to it must point to a 0 value. // This function updates the value to use it in subsequent calls. // Returns: // The smaller offset within bitmask A where bitmask B can be put. // uint32_t yr_bitmask_find_non_colliding_offset( YR_BITMASK* a, YR_BITMASK* b, uint32_t len_a, uint32_t len_b, uint32_t* off_a) { uint32_t i, j, k; // Ensure that the first bit of bitmask B is set, as this function does some // optimizations that rely on that. assert(yr_bitmask_is_set(b, 0)); // Skip all slots that are filled with 1s. It's safe to do that because the // first bit of B is 1, so we won't be able to accommodate B at any offset // within such slots. for (i = *off_a / YR_BITMASK_SLOT_BITS; i <= len_a / YR_BITMASK_SLOT_BITS && a[i] == -1L; i++) ; *off_a = i; for (; i <= len_a / YR_BITMASK_SLOT_BITS; i++) { // The slot is filled with 1s, we can safely skip it. if (a[i] == -1L) continue; for (j = 0; j <= yr_min(len_a, YR_BITMASK_SLOT_BITS - 1); j++) { bool found = true; for (k = 0; k <= len_b / YR_BITMASK_SLOT_BITS; k++) { YR_BITMASK m = b[k] << j; if (j > 0 && k > 0) m |= b[k - 1] >> (YR_BITMASK_SLOT_BITS - j); if ((i + k <= len_a / YR_BITMASK_SLOT_BITS) && (m & a[i + k]) != 0) { found = false; break; } } if (found) return i * YR_BITMASK_SLOT_BITS + j; } } return len_a; } yara-4.5.3/libyara/compiler.c000066400000000000000000000721321501365277300160760ustar00rootroot00000000000000/* Copyright (c) 2013-2018. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #ifdef _MSC_VER #include #include #else #include #endif #include #include #include #include #include #include #include #include #include static void _yr_compiler_default_include_free( const char* callback_result_ptr, void* user_data) { if (callback_result_ptr != NULL) { yr_free((void*) callback_result_ptr); } } const char* _yr_compiler_default_include_callback( const char* include_name, const char* calling_rule_filename, const char* calling_rule_namespace, void* user_data) { #ifndef _MSC_VER struct stat stbuf; #endif char* file_buffer; #ifdef _MSC_VER long file_size; #else off_t file_size; #endif int fd = -1; #if defined(_MSC_VER) _sopen_s(&fd, include_name, _O_RDONLY | _O_BINARY, _SH_DENYWR, _S_IREAD); #elif defined(_WIN32) || defined(__CYGWIN__) fd = open(include_name, O_RDONLY | O_BINARY); #else fd = open(include_name, O_RDONLY); #endif if (fd == -1) return NULL; #ifdef _MSC_VER file_size = _filelength(fd); if (file_size == -1) { _close(fd); return NULL; } #else if ((fstat(fd, &stbuf) != 0) || (!S_ISREG(stbuf.st_mode))) { close(fd); return NULL; } file_size = stbuf.st_size; #endif file_buffer = (char*) yr_malloc((size_t) file_size + 1); if (file_buffer == NULL) { #ifdef _MSC_VER _close(fd); #else close(fd); #endif return NULL; } if (file_size != read(fd, file_buffer, (size_t) file_size)) { yr_free(file_buffer); #ifdef _MSC_VER _close(fd); #else close(fd); #endif return NULL; } else { file_buffer[file_size] = '\0'; } #ifdef _MSC_VER _close(fd); #else close(fd); #endif return file_buffer; } //////////////////////////////////////////////////////////////////////////////// // Returns a rule given its index in the rules table. // // The returned pointer is valid as long as no other rule is written to the // table. This is because the write operation may cause the table to be moved to // a different location in memory. Use the pointer only in a limited scope where // you can be sure that no other rule is being written during the pointer's // lifetime. // YR_RULE* _yr_compiler_get_rule_by_idx(YR_COMPILER* compiler, uint32_t rule_idx) { return (YR_RULE*) yr_arena_get_ptr( compiler->arena, YR_RULES_TABLE, rule_idx * sizeof(YR_RULE)); } //////////////////////////////////////////////////////////////////////////////// // Stores some data in the YR_SZ_POOL and returns a reference to it. // // If the same data was already stored in a previous call to this function the // data is not written again, a reference to the existing data is returned // instead. // int _yr_compiler_store_data( YR_COMPILER* compiler, const void* data, size_t data_length, YR_ARENA_REF* ref) { // Check if the data is already in YR_SZ_POOL by using a hash table. uint32_t offset = yr_hash_table_lookup_uint32_raw_key( compiler->sz_table, data, data_length, NULL); if (offset == UINT32_MAX) { // The data was not previously written to YR_SZ_POOL, write it and store // the reference's offset in the hash table. Storing the buffer number // is not necessary, it's always YR_SZ_POOL. FAIL_ON_ERROR(yr_arena_write_data( compiler->arena, YR_SZ_POOL, data, data_length, ref)); FAIL_ON_ERROR(yr_hash_table_add_uint32_raw_key( compiler->sz_table, data, data_length, NULL, ref->offset)); } else { ref->buffer_id = YR_SZ_POOL; ref->offset = offset; } return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Similar to _yr_compiler_store_data, but receives a null-terminated string. // int _yr_compiler_store_string( YR_COMPILER* compiler, const char* string, YR_ARENA_REF* ref) { return _yr_compiler_store_data( compiler, (void*) string, strlen(string) + 1, // include the null terminator ref); } YR_API int yr_compiler_create(YR_COMPILER** compiler) { int result; YR_COMPILER* new_compiler; new_compiler = (YR_COMPILER*) yr_calloc(1, sizeof(YR_COMPILER)); if (new_compiler == NULL) return ERROR_INSUFFICIENT_MEMORY; new_compiler->current_rule_idx = UINT32_MAX; new_compiler->next_rule_idx = 0; new_compiler->current_string_idx = 0; new_compiler->current_namespace_idx = 0; new_compiler->current_meta_idx = 0; new_compiler->num_namespaces = 0; new_compiler->errors = 0; new_compiler->callback = NULL; new_compiler->rules = NULL; new_compiler->include_callback = _yr_compiler_default_include_callback; new_compiler->incl_clbk_user_data = NULL; new_compiler->include_free = _yr_compiler_default_include_free; new_compiler->re_ast_callback = NULL; new_compiler->re_ast_clbk_user_data = NULL; new_compiler->last_error = ERROR_SUCCESS; new_compiler->last_error_line = 0; new_compiler->strict_escape = false; new_compiler->current_line = 0; new_compiler->file_name_stack_ptr = 0; new_compiler->fixup_stack_head = NULL; new_compiler->loop_index = -1; new_compiler->loop_for_of_var_index = -1; new_compiler->atoms_config.get_atom_quality = yr_atoms_heuristic_quality; new_compiler->atoms_config.quality_warning_threshold = YR_ATOM_QUALITY_WARNING_THRESHOLD; result = yr_hash_table_create(5000, &new_compiler->rules_table); if (result == ERROR_SUCCESS) result = yr_hash_table_create(1000, &new_compiler->objects_table); if (result == ERROR_SUCCESS) result = yr_hash_table_create(10000, &new_compiler->strings_table); if (result == ERROR_SUCCESS) result = yr_hash_table_create( 1000, &new_compiler->wildcard_identifiers_table); if (result == ERROR_SUCCESS) result = yr_hash_table_create(10000, &new_compiler->sz_table); if (result == ERROR_SUCCESS) result = yr_arena_create(YR_NUM_SECTIONS, 1048576, &new_compiler->arena); if (result == ERROR_SUCCESS) result = yr_ac_automaton_create( new_compiler->arena, &new_compiler->automaton); if (result == ERROR_SUCCESS) { *compiler = new_compiler; } else // if error, do cleanup { yr_compiler_destroy(new_compiler); } return result; } YR_API void yr_compiler_destroy(YR_COMPILER* compiler) { if (compiler->arena != NULL) yr_arena_release(compiler->arena); if (compiler->automaton != NULL) yr_ac_automaton_destroy(compiler->automaton); if (compiler->rules_table != NULL) yr_hash_table_destroy(compiler->rules_table, NULL); if (compiler->strings_table != NULL) yr_hash_table_destroy(compiler->strings_table, NULL); if (compiler->wildcard_identifiers_table != NULL) yr_hash_table_destroy(compiler->wildcard_identifiers_table, NULL); if (compiler->sz_table != NULL) yr_hash_table_destroy(compiler->sz_table, NULL); if (compiler->objects_table != NULL) yr_hash_table_destroy( compiler->objects_table, (YR_HASH_TABLE_FREE_VALUE_FUNC) yr_object_destroy); if (compiler->atoms_config.free_quality_table) yr_free(compiler->atoms_config.quality_table); for (int i = 0; i < compiler->file_name_stack_ptr; i++) yr_free(compiler->file_name_stack[i]); YR_FIXUP* fixup = compiler->fixup_stack_head; while (fixup != NULL) { YR_FIXUP* next_fixup = fixup->next; yr_free(fixup); fixup = next_fixup; } yr_free(compiler); } YR_API void yr_compiler_set_callback( YR_COMPILER* compiler, YR_COMPILER_CALLBACK_FUNC callback, void* user_data) { compiler->callback = callback; compiler->user_data = user_data; } YR_API void yr_compiler_set_include_callback( YR_COMPILER* compiler, YR_COMPILER_INCLUDE_CALLBACK_FUNC include_callback, YR_COMPILER_INCLUDE_FREE_FUNC include_free, void* user_data) { compiler->include_callback = include_callback; compiler->include_free = include_free; compiler->incl_clbk_user_data = user_data; } YR_API void yr_compiler_set_re_ast_callback( YR_COMPILER* compiler, YR_COMPILER_RE_AST_CALLBACK_FUNC re_ast_callback, void* user_data) { compiler->re_ast_callback = re_ast_callback; compiler->re_ast_clbk_user_data = user_data; } //////////////////////////////////////////////////////////////////////////////// // This function allows to specify an atom quality table to be used by the // compiler for choosing the best atoms from regular expressions and strings. // When a quality table is set, the compiler uses yr_atoms_table_quality // instead of yr_atoms_heuristic_quality for computing atom quality. The table // has an arbitrary number of entries, each composed of YR_MAX_ATOM_LENGTH + 1 // bytes. The first YR_MAX_ATOM_LENGTH bytes from each entry are the atom's // ones, and the remaining byte is a value in the range 0-255 determining the // atom's quality. Entries must be lexicographically sorted by atom in ascending // order. // // [ atom (YR_MAX_ATOM_LENGTH bytes) ] [ quality (1 byte) ] // // [ 00 00 .. 00 00 ] [ 00 ] // [ 00 00 .. 00 01 ] [ 45 ] // [ 00 00 .. 00 02 ] [ 13 ] // ... // [ FF FF .. FF FF ] [ 03 ] // // The "table" argument must point to a buffer containing the quality in // the format explained above, and "entries" must contain the number of entries // in the table. The table can not be freed while the compiler is in use, the // caller is responsible for freeing the table. // // The "warning_threshold" argument must be a number between 0 and 255, if some // atom chosen for a string have a quality below the specified threshold a // warning like " is slowing down scanning" is shown. // YR_API void yr_compiler_set_atom_quality_table( YR_COMPILER* compiler, const void* table, int entries, unsigned char warning_threshold) { compiler->atoms_config.free_quality_table = false; compiler->atoms_config.quality_warning_threshold = warning_threshold; compiler->atoms_config.get_atom_quality = yr_atoms_table_quality; compiler->atoms_config.quality_table_entries = entries; compiler->atoms_config.quality_table = (YR_ATOM_QUALITY_TABLE_ENTRY*) table; } //////////////////////////////////////////////////////////////////////////////// // Load an atom quality table from a file. The file's content must have the // format explained in the description for yr_compiler_set_atom_quality_table. // YR_API int yr_compiler_load_atom_quality_table( YR_COMPILER* compiler, const char* filename, unsigned char warning_threshold) { long file_size; int entries; void* table; FILE* fh = fopen(filename, "rb"); if (fh == NULL) return ERROR_COULD_NOT_OPEN_FILE; fseek(fh, 0L, SEEK_END); file_size = ftell(fh); fseek(fh, 0L, SEEK_SET); if (file_size == -1L) { fclose(fh); return ERROR_COULD_NOT_READ_FILE; } table = yr_malloc(file_size); if (table == NULL) { fclose(fh); return ERROR_INSUFFICIENT_MEMORY; } entries = (int) file_size / sizeof(YR_ATOM_QUALITY_TABLE_ENTRY); if (fread(table, sizeof(YR_ATOM_QUALITY_TABLE_ENTRY), entries, fh) != entries) { fclose(fh); yr_free(table); return ERROR_COULD_NOT_READ_FILE; } fclose(fh); yr_compiler_set_atom_quality_table( compiler, table, entries, warning_threshold); compiler->atoms_config.free_quality_table = true; return ERROR_SUCCESS; } int _yr_compiler_push_file_name(YR_COMPILER* compiler, const char* file_name) { char* str; int i; for (i = 0; i < compiler->file_name_stack_ptr; i++) { if (strcmp(file_name, compiler->file_name_stack[i]) == 0) return ERROR_INCLUDES_CIRCULAR_REFERENCE; } if (compiler->file_name_stack_ptr == YR_MAX_INCLUDE_DEPTH) return ERROR_INCLUDE_DEPTH_EXCEEDED; str = yr_strdup(file_name); if (str == NULL) return ERROR_INSUFFICIENT_MEMORY; compiler->file_name_stack[compiler->file_name_stack_ptr] = str; compiler->file_name_stack_ptr++; return ERROR_SUCCESS; } void _yr_compiler_pop_file_name(YR_COMPILER* compiler) { if (compiler->file_name_stack_ptr > 0) { compiler->file_name_stack_ptr--; yr_free(compiler->file_name_stack[compiler->file_name_stack_ptr]); compiler->file_name_stack[compiler->file_name_stack_ptr] = NULL; } } int _yr_compiler_get_var_frame(YR_COMPILER* compiler) { int i, result = 0; for (i = 0; i < compiler->loop_index; i++) { result += compiler->loop[i].vars_count + compiler->loop[i].vars_internal_count; } return result; } YR_API char* yr_compiler_get_current_file_name(YR_COMPILER* compiler) { if (compiler->file_name_stack_ptr > 0) { return compiler->file_name_stack[compiler->file_name_stack_ptr - 1]; } else { return NULL; } } static int _yr_compiler_set_namespace( YR_COMPILER* compiler, const char* namespace_) { YR_NAMESPACE* ns = (YR_NAMESPACE*) yr_arena_get_ptr( compiler->arena, YR_NAMESPACES_TABLE, 0); bool found = false; for (int i = 0; i < compiler->num_namespaces; i++, ns++) { if (strcmp(ns->name, namespace_) == 0) { found = true; compiler->current_namespace_idx = i; break; } } if (!found) { YR_ARENA_REF ref; FAIL_ON_ERROR(yr_arena_allocate_struct( compiler->arena, YR_NAMESPACES_TABLE, sizeof(YR_NAMESPACE), &ref, offsetof(YR_NAMESPACE, name), EOL)); ns = (YR_NAMESPACE*) yr_arena_ref_to_ptr(compiler->arena, &ref); FAIL_ON_ERROR(_yr_compiler_store_string(compiler, namespace_, &ref)); ns->name = (const char*) yr_arena_ref_to_ptr(compiler->arena, &ref); ns->idx = compiler->num_namespaces; compiler->current_namespace_idx = compiler->num_namespaces; compiler->num_namespaces++; } return ERROR_SUCCESS; } YR_API int yr_compiler_add_file( YR_COMPILER* compiler, FILE* rules_file, const char* namespace_, const char* file_name) { int result; // Don't allow yr_compiler_add_file() after // yr_compiler_get_rules() has been called. assert(compiler->rules == NULL); // Don't allow calls to yr_compiler_add_file() if a previous call to // yr_compiler_add_XXXX failed. assert(compiler->errors == 0); if (namespace_ != NULL) compiler->last_error = _yr_compiler_set_namespace(compiler, namespace_); else compiler->last_error = _yr_compiler_set_namespace(compiler, "default"); if (compiler->last_error == ERROR_SUCCESS && file_name != NULL) compiler->last_error = _yr_compiler_push_file_name(compiler, file_name); if (compiler->last_error != ERROR_SUCCESS) return ++compiler->errors; result = yr_lex_parse_rules_file(rules_file, compiler); if (file_name != NULL) _yr_compiler_pop_file_name(compiler); return result; } YR_API int yr_compiler_add_fd( YR_COMPILER* compiler, YR_FILE_DESCRIPTOR rules_fd, const char* namespace_, const char* file_name) { int result; // Don't allow yr_compiler_add_fd() after // yr_compiler_get_rules() has been called. assert(compiler->rules == NULL); // Don't allow calls to yr_compiler_add_fd() if a previous call to // yr_compiler_add_XXXX failed. assert(compiler->errors == 0); if (namespace_ != NULL) compiler->last_error = _yr_compiler_set_namespace(compiler, namespace_); else compiler->last_error = _yr_compiler_set_namespace(compiler, "default"); if (compiler->last_error == ERROR_SUCCESS && file_name != NULL) compiler->last_error = _yr_compiler_push_file_name(compiler, file_name); if (compiler->last_error != ERROR_SUCCESS) return ++compiler->errors; result = yr_lex_parse_rules_fd(rules_fd, compiler); if (file_name != NULL) _yr_compiler_pop_file_name(compiler); return result; } YR_API int yr_compiler_add_bytes( YR_COMPILER* compiler, const void* rules_data, size_t rules_size, const char* namespace_) { // Don't allow calls to yr_compiler_add_bytes() after // yr_compiler_get_rules() has been called. assert(compiler->rules == NULL); // Don't allow calls to yr_compiler_add_bytes() if a previous call to // yr_compiler_add_XXXX failed. assert(compiler->errors == 0); if (namespace_ != NULL) compiler->last_error = _yr_compiler_set_namespace(compiler, namespace_); else compiler->last_error = _yr_compiler_set_namespace(compiler, "default"); if (compiler->last_error != ERROR_SUCCESS) return ++compiler->errors; return yr_lex_parse_rules_bytes(rules_data, rules_size, compiler); } YR_API int yr_compiler_add_string( YR_COMPILER* compiler, const char* rules_string, const char* namespace_) { // Don't allow calls to yr_compiler_add_string() after // yr_compiler_get_rules() has been called. assert(compiler->rules == NULL); // Don't allow calls to yr_compiler_add_string() if a previous call to // yr_compiler_add_XXXX failed. assert(compiler->errors == 0); if (namespace_ != NULL) compiler->last_error = _yr_compiler_set_namespace(compiler, namespace_); else compiler->last_error = _yr_compiler_set_namespace(compiler, "default"); if (compiler->last_error != ERROR_SUCCESS) return ++compiler->errors; return yr_lex_parse_rules_string(rules_string, compiler); } static int _yr_compiler_compile_rules(YR_COMPILER* compiler) { YR_RULE null_rule; YR_EXTERNAL_VARIABLE null_external; uint8_t halt = OP_HALT; // Write halt instruction at the end of code. FAIL_ON_ERROR(yr_arena_write_data( compiler->arena, YR_CODE_SECTION, &halt, sizeof(uint8_t), NULL)); // Write a null rule indicating the end. memset(&null_rule, 0xFA, sizeof(YR_RULE)); null_rule.flags = RULE_FLAGS_NULL; FAIL_ON_ERROR(yr_arena_write_data( compiler->arena, YR_RULES_TABLE, &null_rule, sizeof(YR_RULE), NULL)); // Write a null external indicating the end. memset(&null_external, 0xFA, sizeof(YR_EXTERNAL_VARIABLE)); null_external.type = EXTERNAL_VARIABLE_TYPE_NULL; FAIL_ON_ERROR(yr_arena_write_data( compiler->arena, YR_EXTERNAL_VARIABLES_TABLE, &null_external, sizeof(YR_EXTERNAL_VARIABLE), NULL)); // Write Aho-Corasick automaton to arena. FAIL_ON_ERROR(yr_ac_compile(compiler->automaton, compiler->arena)); YR_ARENA_REF ref; FAIL_ON_ERROR(yr_arena_allocate_struct( compiler->arena, YR_SUMMARY_SECTION, sizeof(YR_SUMMARY), &ref, EOL)); YR_SUMMARY* summary = (YR_SUMMARY*) yr_arena_ref_to_ptr( compiler->arena, &ref); summary->num_namespaces = compiler->num_namespaces; summary->num_rules = compiler->next_rule_idx; summary->num_strings = compiler->current_string_idx; return yr_rules_from_arena(compiler->arena, &compiler->rules); } YR_API int yr_compiler_get_rules(YR_COMPILER* compiler, YR_RULES** rules) { // Don't allow calls to yr_compiler_get_rules() if a previous call to // yr_compiler_add_XXXX failed. assert(compiler->errors == 0); *rules = NULL; if (compiler->rules == NULL) FAIL_ON_ERROR(_yr_compiler_compile_rules(compiler)); *rules = compiler->rules; return ERROR_SUCCESS; } static int _yr_compiler_define_variable( YR_COMPILER* compiler, YR_EXTERNAL_VARIABLE* external) { YR_EXTERNAL_VARIABLE* ext; YR_OBJECT* object; if (external->identifier == NULL) return ERROR_INVALID_ARGUMENT; object = (YR_OBJECT*) yr_hash_table_lookup( compiler->objects_table, external->identifier, NULL); if (object != NULL) return ERROR_DUPLICATED_EXTERNAL_VARIABLE; YR_ARENA_REF ext_ref; YR_ARENA_REF ref; FAIL_ON_ERROR(yr_arena_allocate_struct( compiler->arena, YR_EXTERNAL_VARIABLES_TABLE, sizeof(YR_EXTERNAL_VARIABLE), &ext_ref, offsetof(YR_EXTERNAL_VARIABLE, identifier), EOL)); ext = (YR_EXTERNAL_VARIABLE*) yr_arena_ref_to_ptr(compiler->arena, &ext_ref); FAIL_ON_ERROR( _yr_compiler_store_string(compiler, external->identifier, &ref)); ext->identifier = (const char*) yr_arena_ref_to_ptr(compiler->arena, &ref); ext->type = external->type; ext->value = external->value; if (external->type == EXTERNAL_VARIABLE_TYPE_STRING) { if (external->value.s == NULL) return ERROR_INVALID_ARGUMENT; FAIL_ON_ERROR(_yr_compiler_store_string(compiler, external->value.s, &ref)); FAIL_ON_ERROR(yr_arena_make_ptr_relocatable( compiler->arena, YR_EXTERNAL_VARIABLES_TABLE, ext_ref.offset + offsetof(YR_EXTERNAL_VARIABLE, value.s), EOL)); ext->value.s = (char*) yr_arena_ref_to_ptr(compiler->arena, &ref); } FAIL_ON_ERROR(yr_object_from_external_variable(external, &object)); FAIL_ON_ERROR_WITH_CLEANUP( yr_hash_table_add( compiler->objects_table, external->identifier, NULL, (void*) object), yr_object_destroy(object)); return ERROR_SUCCESS; } YR_API int yr_compiler_define_integer_variable( YR_COMPILER* compiler, const char* identifier, int64_t value) { YR_EXTERNAL_VARIABLE external; external.type = EXTERNAL_VARIABLE_TYPE_INTEGER; external.identifier = identifier; external.value.i = value; FAIL_ON_ERROR(_yr_compiler_define_variable(compiler, &external)); return ERROR_SUCCESS; } YR_API int yr_compiler_define_boolean_variable( YR_COMPILER* compiler, const char* identifier, int value) { YR_EXTERNAL_VARIABLE external; external.type = EXTERNAL_VARIABLE_TYPE_BOOLEAN; external.identifier = identifier; external.value.i = value; FAIL_ON_ERROR(_yr_compiler_define_variable(compiler, &external)); return ERROR_SUCCESS; } YR_API int yr_compiler_define_float_variable( YR_COMPILER* compiler, const char* identifier, double value) { YR_EXTERNAL_VARIABLE external; external.type = EXTERNAL_VARIABLE_TYPE_FLOAT; external.identifier = identifier; external.value.f = value; FAIL_ON_ERROR(_yr_compiler_define_variable(compiler, &external)); return ERROR_SUCCESS; } YR_API int yr_compiler_define_string_variable( YR_COMPILER* compiler, const char* identifier, const char* value) { YR_EXTERNAL_VARIABLE external; external.type = EXTERNAL_VARIABLE_TYPE_STRING; external.identifier = identifier; external.value.s = (char*) value; FAIL_ON_ERROR(_yr_compiler_define_variable(compiler, &external)); return ERROR_SUCCESS; } YR_API char* yr_compiler_get_error_message( YR_COMPILER* compiler, char* buffer, int buffer_size) { uint32_t max_strings_per_rule; switch (compiler->last_error) { case ERROR_INSUFFICIENT_MEMORY: snprintf(buffer, buffer_size, "not enough memory"); break; case ERROR_DUPLICATED_IDENTIFIER: snprintf( buffer, buffer_size, "duplicated identifier \"%s\"", compiler->last_error_extra_info); break; case ERROR_DUPLICATED_STRING_IDENTIFIER: snprintf( buffer, buffer_size, "duplicated string identifier \"%s\"", compiler->last_error_extra_info); break; case ERROR_DUPLICATED_TAG_IDENTIFIER: snprintf( buffer, buffer_size, "duplicated tag identifier \"%s\"", compiler->last_error_extra_info); break; case ERROR_DUPLICATED_META_IDENTIFIER: snprintf( buffer, buffer_size, "duplicated metadata identifier \"%s\"", compiler->last_error_extra_info); break; case ERROR_DUPLICATED_LOOP_IDENTIFIER: snprintf( buffer, buffer_size, "duplicated loop identifier \"%s\"", compiler->last_error_extra_info); break; case ERROR_UNDEFINED_STRING: snprintf( buffer, buffer_size, "undefined string \"%s\"", compiler->last_error_extra_info); break; case ERROR_UNDEFINED_IDENTIFIER: snprintf( buffer, buffer_size, "undefined identifier \"%s\"", compiler->last_error_extra_info); break; case ERROR_UNREFERENCED_STRING: snprintf( buffer, buffer_size, "unreferenced string \"%s\"", compiler->last_error_extra_info); break; case ERROR_EMPTY_STRING: snprintf( buffer, buffer_size, "empty string \"%s\"", compiler->last_error_extra_info); break; case ERROR_NOT_A_STRUCTURE: snprintf( buffer, buffer_size, "\"%s\" is not a structure", compiler->last_error_extra_info); break; case ERROR_NOT_INDEXABLE: snprintf( buffer, buffer_size, "\"%s\" is not an array or dictionary", compiler->last_error_extra_info); break; case ERROR_NOT_A_FUNCTION: snprintf( buffer, buffer_size, "\"%s\" is not a function", compiler->last_error_extra_info); break; case ERROR_INVALID_FIELD_NAME: snprintf( buffer, buffer_size, "invalid field name \"%s\"", compiler->last_error_extra_info); break; case ERROR_MISPLACED_ANONYMOUS_STRING: snprintf(buffer, buffer_size, "wrong use of anonymous string"); break; case ERROR_INCLUDES_CIRCULAR_REFERENCE: snprintf(buffer, buffer_size, "include circular reference"); break; case ERROR_INCLUDE_DEPTH_EXCEEDED: snprintf(buffer, buffer_size, "too many levels of included rules"); break; case ERROR_LOOP_NESTING_LIMIT_EXCEEDED: snprintf(buffer, buffer_size, "loop nesting limit exceeded"); break; case ERROR_NESTED_FOR_OF_LOOP: snprintf( buffer, buffer_size, "'for of ' loops can't be nested"); break; case ERROR_UNKNOWN_MODULE: snprintf( buffer, buffer_size, "unknown module \"%s\"", compiler->last_error_extra_info); break; case ERROR_INVALID_MODULE_NAME: snprintf( buffer, buffer_size, "invalid module name \"%s\"", compiler->last_error_extra_info); break; case ERROR_DUPLICATED_STRUCTURE_MEMBER: snprintf(buffer, buffer_size, "duplicated structure member"); break; case ERROR_WRONG_ARGUMENTS: snprintf( buffer, buffer_size, "wrong arguments for function \"%s\"", compiler->last_error_extra_info); break; case ERROR_WRONG_RETURN_TYPE: snprintf(buffer, buffer_size, "wrong return type for overloaded function"); break; case ERROR_INVALID_HEX_STRING: case ERROR_INVALID_REGULAR_EXPRESSION: case ERROR_SYNTAX_ERROR: case ERROR_WRONG_TYPE: case ERROR_INVALID_MODIFIER: case ERROR_INVALID_PERCENTAGE: snprintf(buffer, buffer_size, "%s", compiler->last_error_extra_info); break; case ERROR_INTERNAL_FATAL_ERROR: snprintf(buffer, buffer_size, "internal fatal error"); break; case ERROR_DIVISION_BY_ZERO: snprintf(buffer, buffer_size, "division by zero"); break; case ERROR_REGULAR_EXPRESSION_TOO_LARGE: snprintf(buffer, buffer_size, "regular expression is too large"); break; case ERROR_REGULAR_EXPRESSION_TOO_COMPLEX: snprintf(buffer, buffer_size, "regular expression is too complex"); break; case ERROR_TOO_MANY_STRINGS: yr_get_configuration_uint32( YR_CONFIG_MAX_STRINGS_PER_RULE, &max_strings_per_rule); snprintf( buffer, buffer_size, "too many strings in rule \"%s\" (limit: %d)", compiler->last_error_extra_info, max_strings_per_rule); break; case ERROR_INTEGER_OVERFLOW: snprintf( buffer, buffer_size, "integer overflow in \"%s\"", compiler->last_error_extra_info); break; case ERROR_COULD_NOT_READ_FILE: snprintf(buffer, buffer_size, "could not read file"); break; case ERROR_DUPLICATED_MODIFIER: snprintf(buffer, buffer_size, "duplicated modifier"); break; case ERROR_IDENTIFIER_MATCHES_WILDCARD: snprintf( buffer, buffer_size, "rule identifier \"%s\" matches previously used wildcard rule set", compiler->last_error_extra_info); break; case ERROR_INVALID_VALUE: snprintf( buffer, buffer_size, "invalid value in condition: \"%s\"", compiler->last_error_extra_info); break; } return buffer; } yara-4.5.3/libyara/crypto.h000066400000000000000000000127411501365277300156110ustar00rootroot00000000000000/* Copyright (c) 2017. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_CRYPTO_H #define YR_CRYPTO_H #define YR_MD5_LEN 16 #define YR_SHA1_LEN 20 #define YR_SHA256_LEN 32 #if defined(HAVE_LIBCRYPTO) #include #include typedef EVP_MD_CTX *yr_md5_ctx; typedef EVP_MD_CTX *yr_sha1_ctx; typedef EVP_MD_CTX *yr_sha256_ctx; #define yr_md5_init(ctx) \ { \ *ctx = EVP_MD_CTX_create(); \ EVP_DigestInit(*ctx, EVP_md5()); \ } #define yr_md5_update(ctx, data, len) EVP_DigestUpdate(*ctx, data, len) #define yr_md5_final(digest, ctx) \ { \ unsigned int len = YR_MD5_LEN; \ EVP_DigestFinal(*ctx, digest, &len); \ EVP_MD_CTX_destroy(*ctx); \ } #define yr_sha1_init(ctx) \ { \ *ctx = EVP_MD_CTX_create(); \ EVP_DigestInit(*ctx, EVP_sha1()); \ } #define yr_sha1_update(ctx, data, len) EVP_DigestUpdate(*ctx, data, len) #define yr_sha1_final(digest, ctx) \ { \ unsigned int len = YR_SHA1_LEN; \ EVP_DigestFinal(*ctx, digest, &len); \ EVP_MD_CTX_destroy(*ctx); \ } #define yr_sha256_init(ctx) \ { \ *ctx = EVP_MD_CTX_create(); \ EVP_DigestInit(*ctx, EVP_sha256()); \ } #define yr_sha256_update(ctx, data, len) EVP_DigestUpdate(*ctx, data, len) #define yr_sha256_final(digest, ctx) \ { \ unsigned int len = YR_SHA256_LEN; \ EVP_DigestFinal(*ctx, digest, &len); \ EVP_MD_CTX_destroy(*ctx); \ } #elif defined(HAVE_WINCRYPT_H) #include #include extern HCRYPTPROV yr_cryptprov; typedef HCRYPTHASH yr_md5_ctx; typedef HCRYPTHASH yr_sha1_ctx; typedef HCRYPTHASH yr_sha256_ctx; #define yr_md5_init(ctx) CryptCreateHash(yr_cryptprov, CALG_MD5, 0, 0, ctx) #define yr_md5_update(ctx, data, len) \ CryptHashData(*ctx, (const BYTE*) data, len, 0) #define yr_md5_final(digest, ctx) \ { \ DWORD len = YR_MD5_LEN; \ CryptGetHashParam(*ctx, HP_HASHVAL, digest, &len, 0); \ CryptDestroyHash(*ctx); \ } #define yr_sha1_init(ctx) CryptCreateHash(yr_cryptprov, CALG_SHA1, 0, 0, ctx) #define yr_sha1_update(ctx, data, len) \ CryptHashData(*ctx, (const BYTE*) data, len, 0) #define yr_sha1_final(digest, ctx) \ { \ DWORD len = YR_SHA1_LEN; \ CryptGetHashParam(*ctx, HP_HASHVAL, digest, &len, 0); \ CryptDestroyHash(*ctx); \ } #define yr_sha256_init(ctx) \ CryptCreateHash(yr_cryptprov, CALG_SHA_256, 0, 0, ctx) #define yr_sha256_update(ctx, data, len) \ CryptHashData(*ctx, (const BYTE*) data, len, 0) #define yr_sha256_final(digest, ctx) \ { \ DWORD len = YR_SHA256_LEN; \ CryptGetHashParam(*ctx, HP_HASHVAL, digest, &len, 0); \ CryptDestroyHash(*ctx); \ } #elif defined(HAVE_COMMONCRYPTO_COMMONCRYPTO_H) #include typedef CC_MD5_CTX yr_md5_ctx; typedef CC_SHA1_CTX yr_sha1_ctx; typedef CC_SHA256_CTX yr_sha256_ctx; #define yr_md5_init(ctx) CC_MD5_Init(ctx) #define yr_md5_update(ctx, data, len) CC_MD5_Update(ctx, data, len) #define yr_md5_final(digest, ctx) CC_MD5_Final(digest, ctx) #define yr_sha1_init(ctx) CC_SHA1_Init(ctx) #define yr_sha1_update(ctx, data, len) CC_SHA1_Update(ctx, data, len) #define yr_sha1_final(digest, ctx) CC_SHA1_Final(digest, ctx) #define yr_sha256_init(ctx) CC_SHA256_Init(ctx) #define yr_sha256_update(ctx, data, len) CC_SHA256_Update(ctx, data, len) #define yr_sha256_final(digest, ctx) CC_SHA256_Final(digest, ctx) #endif #endif yara-4.5.3/libyara/endian.c000066400000000000000000000041641501365277300155220ustar00rootroot00000000000000/* Copyright (c) 2017. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include uint16_t _yr_bswap16(uint16_t x) { return (x >> 8 | x << 8); } uint32_t _yr_bswap32(uint32_t x) { return ( (((x) &0xff000000) >> 24) | (((x) &0x00ff0000) >> 8) | (((x) &0x0000ff00) << 8) | (((x) &0x000000ff) << 24)); } uint64_t _yr_bswap64(uint64_t x) { return ( (((x) &0xff00000000000000ull) >> 56) | (((x) &0x00ff000000000000ull) >> 40) | (((x) &0x0000ff0000000000ull) >> 24) | (((x) &0x000000ff00000000ull) >> 8) | (((x) &0x00000000ff000000ull) << 8) | (((x) &0x0000000000ff0000ull) << 24) | (((x) &0x000000000000ff00ull) << 40) | (((x) &0x00000000000000ffull) << 56)); } yara-4.5.3/libyara/exception.h000066400000000000000000000320361501365277300162660ustar00rootroot00000000000000/* Copyright (c) 2015. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_EXCEPTION_H #define YR_EXCEPTION_H #include #include typedef struct { void* memfault_from; void* memfault_to; void* jump_back; } jumpinfo; #if _WIN32 || __CYGWIN__ #include // If compiling with Microsoft's compiler use structured exception handling. #ifdef _MSC_VER #include static LONG CALLBACK exception_handler(PEXCEPTION_POINTERS ExceptionInfo) { switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { case EXCEPTION_IN_PAGE_ERROR: case EXCEPTION_ACCESS_VIOLATION: return EXCEPTION_EXECUTE_HANDLER; } return EXCEPTION_CONTINUE_SEARCH; } #define YR_TRYCATCH(_do_, _try_clause_, _catch_clause_) \ do \ { \ if (_do_) \ { \ __try \ { \ _try_clause_ \ } \ __except (exception_handler(GetExceptionInformation())) \ { \ _catch_clause_ \ } \ } \ else \ { \ _try_clause_ \ } \ } while (0) #else // If not compiling with Microsoft's compiler use vectored exception handling. #include static LONG CALLBACK exception_handler(PEXCEPTION_POINTERS ExceptionInfo) { jumpinfo* jump_info; switch (ExceptionInfo->ExceptionRecord->ExceptionCode) { case EXCEPTION_IN_PAGE_ERROR: jump_info = (jumpinfo*) yr_thread_storage_get_value(&yr_trycatch_trampoline_tls); if (jump_info != NULL) { void* fault_address = (void*) ExceptionInfo->ExceptionRecord->ExceptionInformation[1]; if (jump_info->memfault_from <= fault_address && jump_info->memfault_to > fault_address) { longjmp(*(jmp_buf*)jump_info->jump_back, 1); } } } return EXCEPTION_CONTINUE_SEARCH; } #define YR_TRYCATCH(_do_, _try_clause_, _catch_clause_) \ do \ { \ if (_do_) \ { \ jumpinfo jump_info; \ jump_info.memfault_from = 0; \ jump_info.memfault_to = 0; \ jmp_buf jb; \ jump_info.jump_back = (void*) &jb; \ /* Store pointer to sigjmp_buf in TLS */ \ yr_thread_storage_set_value(&yr_trycatch_trampoline_tls, &jump_info); \ HANDLE exh = AddVectoredExceptionHandler(1, exception_handler); \ if (setjmp(jb) == 0) \ { \ _try_clause_ \ } \ else \ { \ _catch_clause_ \ } \ RemoveVectoredExceptionHandler(exh); \ yr_thread_storage_set_value(&yr_trycatch_trampoline_tls, NULL); \ } \ else \ { \ _try_clause_ \ } \ } while (0) #endif #else #if defined(__APPLE__) || defined(__linux__) || defined(_AIX) #define CATCH_SIGSEGV 0 #define CATCH_SIGBUS 1 #elif defined(BSD) // According to #551, older BSD versions use SIGSEGV for invalid mmap access. // Newer versions, however, use SIGBUS (tested with FreeBSD 13.2 / OpenBSD 7.4). // To be compatible with both, catch SIGBUS and SIGSEGV. #define CATCH_SIGSEGV 1 #define CATCH_SIGBUS 1 #else // For unknown systems, play it safe by catching both #define CATCH_SIGSEGV 1 #define CATCH_SIGBUS 1 #endif #include #include #include #include static void exception_handler(int sig, siginfo_t * info, void *context) { if (sig != SIGBUS && sig != SIGSEGV) { return; } jumpinfo* jump_info = (jumpinfo*) yr_thread_storage_get_value(&yr_trycatch_trampoline_tls); if (jump_info != NULL) { void* fault_address = (void*) info->si_addr; if (jump_info->memfault_from <= fault_address && jump_info->memfault_to > fault_address) { siglongjmp(*(sigjmp_buf*)jump_info->jump_back, 1); } } // If we're here, the signal we received didn't originate from YARA. // In this case, we want to invoke the original signal handler, which may handle the signal. // Lock the exception handler mutex to prevent simultaneous write access while we read the old signal handler pthread_mutex_lock(&exception_handler_mutex); struct sigaction old_handler; if (sig == SIGBUS) old_handler = old_sigbus_exception_handler; else old_handler = old_sigsegv_exception_handler; pthread_mutex_unlock(&exception_handler_mutex); if (old_handler.sa_flags & SA_SIGINFO) { old_handler.sa_sigaction(sig, info, context); } else if (old_handler.sa_handler == SIG_DFL) { // Old handler is the default action. To do this, set the signal handler back to default and raise the signal. // This is fairly volatile - since this is not an atomic operation, signals from other threads might also // cause the default action while we're doing this. However, the default action will typically cause a // process termination anyway. pthread_mutex_lock(&exception_handler_mutex); struct sigaction current_handler; sigaction(sig, &old_handler, ¤t_handler); raise(sig); sigaction(sig, ¤t_handler, NULL); pthread_mutex_unlock(&exception_handler_mutex); } else if (old_handler.sa_handler == SIG_IGN) { // SIG_IGN wants us to ignore the signal return; } else { old_handler.sa_handler(sig); } } // Keep debug output indentation level consistent #if 0 == YR_DEBUG_VERBOSITY #define YR_DEBUG_INDENT_INITIAL 0 #define YR_DEBUG_INDENT_SET(x) ; #else extern YR_TLS int yr_debug_indent; // Ugly, but unfortunately cannot use ifdef macros inside a macro #define YR_DEBUG_INDENT_INITIAL yr_debug_indent #define YR_DEBUG_INDENT_SET(x) yr_debug_indent = (x); #endif typedef struct sigaction sa; #define YR_TRYCATCH(_do_, _try_clause_, _catch_clause_) \ do \ { \ if (_do_) \ { \ pthread_mutex_lock(&exception_handler_mutex); \ if (exception_handler_usecount == 0) \ { \ struct sigaction act; \ /* Set exception handler for SIGSEGV / SIGBUS */ \ act.sa_sigaction = exception_handler; \ act.sa_flags = SA_SIGINFO | SA_ONSTACK; \ sigfillset(&act.sa_mask); \ if (CATCH_SIGBUS) \ sigaction(SIGBUS, &act, &old_sigbus_exception_handler); \ if (CATCH_SIGSEGV) \ sigaction(SIGSEGV, &act, &old_sigsegv_exception_handler); \ } \ exception_handler_usecount++; \ pthread_mutex_unlock(&exception_handler_mutex); \ /* Save the current debug indentation level before the jump. */ \ int yr_debug_indent_before_jump = YR_DEBUG_INDENT_INITIAL; \ jumpinfo ji; \ ji.memfault_from = 0; \ ji.memfault_to = 0; \ sigjmp_buf jb; \ ji.jump_back = (void*) &jb; \ /* Store pointer to jumpinfo in TLS */ \ yr_thread_storage_set_value(&yr_trycatch_trampoline_tls, &ji); \ if (sigsetjmp(jb, 1) == 0) \ { \ _try_clause_ \ } \ else \ { \ /* Restore debug output indentation in case of failure */ \ YR_DEBUG_INDENT_SET(yr_debug_indent_before_jump); \ \ _catch_clause_ \ } \ pthread_mutex_lock(&exception_handler_mutex); \ exception_handler_usecount--; \ if (exception_handler_usecount == 0) \ { \ /* Stop capturing relevant signals */ \ if (CATCH_SIGBUS) \ sigaction(SIGBUS, &old_sigbus_exception_handler, NULL); \ if (CATCH_SIGSEGV) \ sigaction(SIGSEGV, &old_sigsegv_exception_handler, NULL); \ } \ pthread_mutex_unlock(&exception_handler_mutex); \ yr_thread_storage_set_value(&yr_trycatch_trampoline_tls, NULL); \ } \ else \ { \ _try_clause_ \ } \ } while (0) #endif #endif yara-4.5.3/libyara/exec.c000066400000000000000000001760441501365277300152170ustar00rootroot00000000000000/* Copyright (c) 2013-2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MEM_SIZE YR_MAX_LOOP_NESTING*(YR_MAX_LOOP_VARS + YR_INTERNAL_LOOP_VARS) #define push(x) \ if (stack.sp < stack.capacity) \ { \ stack.items[stack.sp++] = (x); \ } \ else \ { \ result = ERROR_EXEC_STACK_OVERFLOW; \ stop = true; \ break; \ } #define pop(x) \ { \ assert(stack.sp > 0); \ x = stack.items[--stack.sp]; \ } #define is_undef(x) IS_UNDEFINED((x).i) #define ensure_defined(x) \ if (is_undef(x)) \ { \ r1.i = YR_UNDEFINED; \ push(r1); \ break; \ } #define ensure_within_mem(x) \ if (x < 0 || x >= MEM_SIZE) \ { \ stop = true; \ result = ERROR_INTERNAL_FATAL_ERROR; \ break; \ } // Make sure that the string pointer is within the rules arena. #define ensure_within_rules_arena(x) \ { \ YR_ARENA_REF ref; \ if (yr_arena_ptr_to_ref(context->rules->arena, x, &ref) == 0) \ { \ stop = true; \ result = ERROR_INTERNAL_FATAL_ERROR; \ break; \ } \ } #define check_object_canary(o) \ if (o->canary != context->canary) \ { \ stop = true; \ result = ERROR_INTERNAL_FATAL_ERROR; \ break; \ } #define little_endian_uint8_t(x) (x) #define little_endian_int8_t(x) (x) #define little_endian_uint16_t(x) yr_le16toh(x) #define little_endian_int16_t(x) yr_le16toh(x) #define little_endian_uint32_t(x) yr_le32toh(x) #define little_endian_int32_t(x) yr_le32toh(x) #define big_endian_uint8_t(x) (x) #define big_endian_int8_t(x) (x) #define big_endian_uint16_t(x) yr_be16toh(x) #define big_endian_int16_t(x) yr_be16toh(x) #define big_endian_uint32_t(x) yr_be32toh(x) #define big_endian_int32_t(x) yr_be32toh(x) #define function_read(type, endianess) \ int64_t read_##type##_##endianess( \ YR_MEMORY_BLOCK_ITERATOR* iterator, size_t offset) \ { \ YR_MEMORY_BLOCK* block = iterator->first(iterator); \ while (block != NULL) \ { \ if (offset >= block->base && block->size >= sizeof(type) && \ offset <= block->base + block->size - sizeof(type)) \ { \ type result; \ const uint8_t* data = yr_fetch_block_data(block); \ if (data == NULL) \ return YR_UNDEFINED; \ result = *(type*) (data + offset - block->base); \ result = endianess##_##type(result); \ return result; \ } \ block = iterator->next(iterator); \ } \ return YR_UNDEFINED; \ }; function_read(uint8_t, little_endian); function_read(uint16_t, little_endian); function_read(uint32_t, little_endian); function_read(int8_t, little_endian); function_read(int16_t, little_endian); function_read(int32_t, little_endian); function_read(uint8_t, big_endian); function_read(uint16_t, big_endian); function_read(uint32_t, big_endian); function_read(int8_t, big_endian); function_read(int16_t, big_endian); function_read(int32_t, big_endian); static const uint8_t* jmp_if(int condition, const uint8_t* ip) { int32_t off = 0; if (condition) { // The condition is true, the instruction pointer (ip) is incremented in // the amount specified by the jump's offset, which is a int32_t following // the jump opcode. The ip is currently past the opcode and pointing to // the offset. // Copy the offset from the instruction stream to a local variable. off = yr_unaligned_u32(ip); // The offset is relative to the jump opcode, but now the ip is one byte // past the opcode, so we need to decrement it by one. off -= 1; } else { // The condition is false, the execution flow proceeds with the instruction // right after the jump. off = sizeof(int32_t); } return ip + off; } static int iter_array_next(YR_ITERATOR* self, YR_VALUE_STACK* stack) { // Check that there's two available slots in the stack, one for the next // item returned by the iterator and another one for the boolean that // indicates if there are more items. if (stack->sp + 1 >= stack->capacity) return ERROR_EXEC_STACK_OVERFLOW; // If the array that must be iterated is undefined stop the iteration right // aways, as if the array would be empty. if (IS_UNDEFINED(self->array_it.array)) goto _stop_iter; // If the current index is equal or larger than array's length the iterator // has reached the end of the array. if (self->array_it.index >= yr_object_array_length(self->array_it.array)) goto _stop_iter; // Push the false value that indicates that the iterator is not exhausted. stack->items[stack->sp++].i = 0; YR_OBJECT* obj = yr_object_array_get_item( self->array_it.array, 0, self->array_it.index); if (obj != NULL) stack->items[stack->sp++].o = obj; else stack->items[stack->sp++].i = YR_UNDEFINED; self->array_it.index++; return ERROR_SUCCESS; _stop_iter: // Push true for indicating the iterator has been exhausted. stack->items[stack->sp++].i = 1; // Push YR_UNDEFINED as a placeholder for the next item. stack->items[stack->sp++].i = YR_UNDEFINED; return ERROR_SUCCESS; } static int iter_dict_next(YR_ITERATOR* self, YR_VALUE_STACK* stack) { // Check that there's three available slots in the stack, two for the next // item returned by the iterator and its key, and another one for the boolean // that indicates if there are more items. if (stack->sp + 2 >= stack->capacity) return ERROR_EXEC_STACK_OVERFLOW; // If the dictionary that must be iterated is undefined, stop the iteration // right away, as if the dictionary would be empty. if (IS_UNDEFINED(self->dict_it.dict)) goto _stop_iter; YR_DICTIONARY_ITEMS* items = object_as_dictionary(self->dict_it.dict)->items; // If the dictionary has no items or the iterator reached the last item, abort // the iteration, if not push the next key and value. if (items == NULL || self->dict_it.index == items->used) goto _stop_iter; // Push the false value that indicates that the iterator is not exhausted. stack->items[stack->sp++].i = 0; if (items->objects[self->dict_it.index].obj != NULL) { stack->items[stack->sp++].o = items->objects[self->dict_it.index].obj; stack->items[stack->sp++].p = items->objects[self->dict_it.index].key; } else { stack->items[stack->sp++].i = YR_UNDEFINED; stack->items[stack->sp++].i = YR_UNDEFINED; } self->dict_it.index++; return ERROR_SUCCESS; _stop_iter: // Push true for indicating the iterator has been exhausted. stack->items[stack->sp++].i = 1; // Push YR_UNDEFINED as a placeholder for the next key and value. stack->items[stack->sp++].i = YR_UNDEFINED; stack->items[stack->sp++].i = YR_UNDEFINED; return ERROR_SUCCESS; } static int iter_int_range_next(YR_ITERATOR* self, YR_VALUE_STACK* stack) { // Check that there's two available slots in the stack, one for the next // item returned by the iterator and another one for the boolean that // indicates if there are more items. if (stack->sp + 1 >= stack->capacity) return ERROR_EXEC_STACK_OVERFLOW; if (!IS_UNDEFINED(self->int_range_it.next) && !IS_UNDEFINED(self->int_range_it.last) && self->int_range_it.next <= self->int_range_it.last) { // Push the false value that indicates that the iterator is not exhausted. stack->items[stack->sp++].i = 0; stack->items[stack->sp++].i = self->int_range_it.next; self->int_range_it.next++; } else { // Push true for indicating the iterator has been exhausted. stack->items[stack->sp++].i = 1; // Push YR_UNDEFINED as a placeholder for the next item. stack->items[stack->sp++].i = YR_UNDEFINED; } return ERROR_SUCCESS; } static int iter_int_enum_next(YR_ITERATOR* self, YR_VALUE_STACK* stack) { // Check that there's two available slots in the stack, one for the next // item returned by the iterator and another one for the boolean that // indicates if there are more items. if (stack->sp + 1 >= stack->capacity) return ERROR_EXEC_STACK_OVERFLOW; if (!IS_UNDEFINED(self->int_enum_it.next) && !IS_UNDEFINED(self->int_enum_it.count) && self->int_enum_it.next < self->int_enum_it.count) { // Push the false value that indicates that the iterator is not exhausted. stack->items[stack->sp++].i = 0; stack->items[stack->sp++].i = self->int_enum_it.items[self->int_enum_it.next]; self->int_enum_it.next++; } else { // Push true for indicating the iterator has been exhausted. stack->items[stack->sp++].i = 1; // Push YR_UNDEFINED as a placeholder for the next item. stack->items[stack->sp++].i = YR_UNDEFINED; } return ERROR_SUCCESS; } static int iter_string_set_next(YR_ITERATOR* self, YR_VALUE_STACK* stack) { // Check that there's two available slots in the stack, one for the next // item returned by the iterator and another one for the boolean that // indicates if there are more items. if (stack->sp + 1 >= stack->capacity) return ERROR_EXEC_STACK_OVERFLOW; // If the current index is equal or larger than array's length the iterator // has reached the end of the array. if (self->string_set_it.index >= self->string_set_it.count) goto _stop_iter; // Push the false value that indicates that the iterator is not exhausted. stack->items[stack->sp++].i = 0; stack->items[stack->sp++].s = self->string_set_it.strings[self->string_set_it.index]; self->string_set_it.index++; return ERROR_SUCCESS; _stop_iter: // Push true for indicating the iterator has been exhausted. stack->items[stack->sp++].i = 1; // Push YR_UNDEFINED as a placeholder for the next item. stack->items[stack->sp++].i = YR_UNDEFINED; return ERROR_SUCCESS; } static int iter_text_string_set_next(YR_ITERATOR* self, YR_VALUE_STACK* stack) { // Check that there's two available slots in the stack, one for the next // item returned by the iterator and another one for the boolean that // indicates if there are more items. if (stack->sp + 1 >= stack->capacity) return ERROR_EXEC_STACK_OVERFLOW; // If the current index is equal or larger than array's length the iterator // has reached the end of the array. if (self->text_string_set_it.index >= self->text_string_set_it.count) goto _stop_iter; // Push the false value that indicates that the iterator is not exhausted. stack->items[stack->sp++].i = 0; stack->items[stack->sp++].ss = self->text_string_set_it.strings[self->text_string_set_it.index]; self->text_string_set_it.index++; return ERROR_SUCCESS; _stop_iter: // Push true for indicating the iterator has been exhausted. stack->items[stack->sp++].i = 1; // Push YR_UNDEFINED as a placeholder for the next item. stack->items[stack->sp++].i = YR_UNDEFINED; return ERROR_SUCCESS; } // Global table that contains the "next" function for different types of // iterators. The reason for using this table is to avoid storing pointers // in the YARA's VM stack. Instead of the pointers we store an index within // this table. static YR_ITERATOR_NEXT_FUNC iter_next_func_table[] = { iter_array_next, iter_dict_next, iter_int_range_next, iter_int_enum_next, iter_string_set_next, iter_text_string_set_next, }; #define ITER_NEXT_ARRAY 0 #define ITER_NEXT_DICT 1 #define ITER_NEXT_INT_RANGE 2 #define ITER_NEXT_INT_ENUM 3 #define ITER_NEXT_STRING_SET 4 #define ITER_NEXT_TEXT_STRING_SET 5 int yr_execute_code(YR_SCAN_CONTEXT* context) { YR_DEBUG_FPRINTF(2, stderr, "+ %s() {\n", __FUNCTION__); const uint8_t* ip = context->rules->code_start; YR_VALUE mem[MEM_SIZE]; YR_VALUE args[YR_MAX_FUNCTION_ARGS]; YR_VALUE r1; YR_VALUE r2; YR_VALUE r3; YR_VALUE r4; YR_VALUE_STACK stack; uint64_t elapsed_time; #ifdef YR_PROFILING_ENABLED uint64_t start_time; #endif uint32_t current_rule_idx = 0; YR_RULE* current_rule = NULL; YR_RULE* rule; YR_MATCH* match; YR_OBJECT_FUNCTION* function; YR_OBJECT** obj_ptr; YR_ARENA* obj_arena; YR_NOTEBOOK* it_notebook; char* identifier; char* args_fmt; int found; int count; int result = ERROR_SUCCESS; int cycle = 0; int obj_count = 0; bool stop = false; uint8_t opcode; yr_get_configuration_uint32(YR_CONFIG_STACK_SIZE, &stack.capacity); stack.sp = 0; stack.items = (YR_VALUE*) yr_malloc(stack.capacity * sizeof(YR_VALUE)); if (stack.items == NULL) return ERROR_INSUFFICIENT_MEMORY; FAIL_ON_ERROR_WITH_CLEANUP( yr_arena_create(1, 512 * sizeof(YR_OBJECT*), &obj_arena), yr_free(stack.items)); FAIL_ON_ERROR_WITH_CLEANUP( yr_notebook_create(512 * sizeof(YR_ITERATOR), &it_notebook), yr_arena_release(obj_arena); yr_free(stack.items)); #ifdef YR_PROFILING_ENABLED start_time = yr_stopwatch_elapsed_ns(&context->stopwatch); #endif #if YR_PARANOID_EXEC memset(mem, 0, MEM_SIZE * sizeof(mem[0])); #endif while (!stop) { // Read the opcode from the address indicated by the instruction pointer. opcode = *ip; // Advance the instruction pointer, which now points past the opcode. ip++; switch (opcode) { case OP_NOP: YR_DEBUG_FPRINTF(2, stderr, "- case OP_NOP: // %s()\n", __FUNCTION__); break; case OP_HALT: YR_DEBUG_FPRINTF(2, stderr, "- case OP_HALT: // %s()\n", __FUNCTION__); assert(stack.sp == 0); // When HALT is reached the stack should be empty. stop = true; break; case OP_ITER_START_ARRAY: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_ITER_START_ARRAY: // %s()\n", __FUNCTION__); r2.p = yr_notebook_alloc(it_notebook, sizeof(YR_ITERATOR)); if (r2.p == NULL) { result = ERROR_INSUFFICIENT_MEMORY; } else { pop(r1); r2.it->array_it.array = r1.o; r2.it->array_it.index = 0; r2.it->next_func_idx = ITER_NEXT_ARRAY; push(r2); } stop = (result != ERROR_SUCCESS); break; case OP_ITER_START_DICT: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_ITER_START_DICT: // %s()\n", __FUNCTION__); r2.p = yr_notebook_alloc(it_notebook, sizeof(YR_ITERATOR)); if (r2.p == NULL) { result = ERROR_INSUFFICIENT_MEMORY; } else { pop(r1); r2.it->dict_it.dict = r1.o; r2.it->dict_it.index = 0; r2.it->next_func_idx = ITER_NEXT_DICT; push(r2); } stop = (result != ERROR_SUCCESS); break; case OP_ITER_START_INT_RANGE: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_ITER_START_INT_RANGE: // %s()\n", __FUNCTION__); // Creates an iterator for an integer range. The higher bound of the // range is at the top of the stack followed by the lower bound. r3.p = yr_notebook_alloc(it_notebook, sizeof(YR_ITERATOR)); if (r3.p == NULL) { result = ERROR_INSUFFICIENT_MEMORY; } else { pop(r2); pop(r1); r3.it->int_range_it.next = r1.i; r3.it->int_range_it.last = r2.i; r3.it->next_func_idx = ITER_NEXT_INT_RANGE; push(r3); } stop = (result != ERROR_SUCCESS); break; case OP_ITER_START_INT_ENUM: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_ITER_START_INT_ENUM: // %s()\n", __FUNCTION__); // Creates an iterator for an integer enumeration. The number of items // in the enumeration is at the top of the stack, followed by the // items in reverse order. pop(r1); r3.p = yr_notebook_alloc( it_notebook, sizeof(YR_ITERATOR) + sizeof(uint64_t) * (size_t) r1.i); if (r3.p == NULL) { result = ERROR_INSUFFICIENT_MEMORY; } else { r3.it->int_enum_it.count = r1.i; r3.it->int_enum_it.next = 0; r3.it->next_func_idx = ITER_NEXT_INT_ENUM; for (int64_t i = r1.i; i > 0; i--) { pop(r2); r3.it->int_enum_it.items[i - 1] = r2.i; } push(r3); } stop = (result != ERROR_SUCCESS); break; case OP_ITER_START_STRING_SET: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_ITER_START_STRING_SET: // %s()\n", __FUNCTION__); pop(r1); r3.p = yr_notebook_alloc( it_notebook, sizeof(YR_ITERATOR) + sizeof(YR_STRING*) * (size_t) r1.i); if (r3.p == NULL) { result = ERROR_INSUFFICIENT_MEMORY; } else { r3.it->string_set_it.count = r1.i; r3.it->string_set_it.index = 0; r3.it->next_func_idx = ITER_NEXT_STRING_SET; for (int64_t i = r1.i; i > 0; i--) { pop(r2); r3.it->string_set_it.strings[i - 1] = r2.s; } // One last pop of the UNDEFINED string pop(r2); push(r3); } stop = (result != ERROR_SUCCESS); break; case OP_ITER_START_TEXT_STRING_SET: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_ITER_START_TEXT_STRING_SET: // %s()\n", __FUNCTION__); pop(r1); r3.p = yr_notebook_alloc( it_notebook, sizeof(YR_ITERATOR) + sizeof(SIZED_STRING*) * (size_t) r1.i); if (r3.p == NULL) { result = ERROR_INSUFFICIENT_MEMORY; } else { r3.it->text_string_set_it.count = r1.i; r3.it->text_string_set_it.index = 0; r3.it->next_func_idx = ITER_NEXT_TEXT_STRING_SET; for (int64_t i = r1.i; i > 0; i--) { pop(r2); r3.it->text_string_set_it.strings[i - 1] = r2.ss; } push(r3); } stop = (result != ERROR_SUCCESS); break; case OP_ITER_NEXT: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_ITER_NEXT: // %s()\n", __FUNCTION__); // Loads the iterator in r1, but leaves the iterator in the stack. pop(r1); push(r1); if (r1.it->next_func_idx < sizeof(iter_next_func_table) / sizeof(YR_ITERATOR_NEXT_FUNC)) { // The iterator's next function is responsible for pushing the next // item in the stack, and a boolean indicating if there are more items // to retrieve. The boolean will be at the top of the stack after // calling "next". result = iter_next_func_table[r1.it->next_func_idx](r1.it, &stack); } else { // next_func_idx is outside the valid range, this should not happend. result = ERROR_INTERNAL_FATAL_ERROR; } stop = (result != ERROR_SUCCESS); break; case OP_ITER_CONDITION: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_ITER_CONDITION: // %s()\n", __FUNCTION__); // Evaluate the iteration condition of the loop. This instruction // evaluates to 1 if the loop should continue and 0 if it shouldn't // (due to short-circuit evaluation). pop(r2); // min. expression - all, any, none, integer pop(r3); // number of true expressions pop(r4); // last expression result // In case of 'all' loop, end once we the body failed if (is_undef(r2)) { r1.i = r4.i != 0 ? 1 : 0; } // In case of 'none' loop, end once the body succeed else if (r2.i == 0) { r1.i = r4.i != 1 ? 1 : 0; } // In case of other loops, end once we satified min. expr. else { r1.i = r3.i + r4.i < r2.i ? 1 : 0; } // Push whether loop should continue and repush // the last expression result push(r1); push(r4); break; case OP_ITER_END: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_ITER_END: // %s()\n", __FUNCTION__); // Evaluate the whole loop. Whether it was successful or not // and whether it satisfied it's quantifier. pop(r2); // min. expression - all, any, none, integer pop(r3); // number of true expressions pop(r4); // number of total iterations // If there was 0 iterations in total, it doesn't // matter what other numbers show. We can't evaluate // the loop as true. if (r4.i == 0) { r1.i = 0; } else if (is_undef(r2)) { r1.i = r3.i == r4.i ? 1 : 0; } else if (r2.i == 0) { r1.i = r3.i == 0 ? 1 : 0; } else { r1.i = r3.i >= r2.i ? 1 : 0; } push(r1); break; case OP_PUSH: YR_DEBUG_FPRINTF(2, stderr, "- case OP_PUSH: // %s()\n", __FUNCTION__); r1.i = yr_unaligned_u64(ip); ip += sizeof(uint64_t); push(r1); break; case OP_PUSH_8: r1.i = *ip; YR_DEBUG_FPRINTF( 2, stderr, "- case OP_PUSH_8: r1.i=%" PRId64 " // %s()\n", r1.i, __FUNCTION__); ip += sizeof(uint8_t); push(r1); break; case OP_PUSH_16: r1.i = yr_unaligned_u16(ip); YR_DEBUG_FPRINTF( 2, stderr, "- case OP_PUSH_16: r1.i=%" PRId64 " // %s()\n", r1.i, __FUNCTION__); ip += sizeof(uint16_t); push(r1); break; case OP_PUSH_32: r1.i = yr_unaligned_u32(ip); YR_DEBUG_FPRINTF( 2, stderr, "- case OP_PUSH_32: r1.i=%" PRId64 " // %s()\n", r1.i, __FUNCTION__); ip += sizeof(uint32_t); push(r1); break; case OP_PUSH_U: YR_DEBUG_FPRINTF(2, stderr, "- case OP_PUSH_U: // %s()\n", __FUNCTION__); r1.i = YR_UNDEFINED; push(r1); break; case OP_POP: YR_DEBUG_FPRINTF(2, stderr, "- case OP_POP: // %s()\n", __FUNCTION__); pop(r1); break; case OP_CLEAR_M: YR_DEBUG_FPRINTF(2, stderr, "- case OP_CLEAR_M: // %s()\n", __FUNCTION__); r1.i = yr_unaligned_u64(ip); ip += sizeof(uint64_t); #if YR_PARANOID_EXEC ensure_within_mem(r1.i); #endif mem[r1.i].i = 0; break; case OP_ADD_M: YR_DEBUG_FPRINTF(2, stderr, "- case OP_ADD_M: // %s()\n", __FUNCTION__); r1.i = yr_unaligned_u64(ip); ip += sizeof(uint64_t); #if YR_PARANOID_EXEC ensure_within_mem(r1.i); #endif pop(r2); if (!is_undef(r2)) mem[r1.i].i += r2.i; break; case OP_INCR_M: YR_DEBUG_FPRINTF(2, stderr, "- case OP_INCR_M: // %s()\n", __FUNCTION__); r1.i = yr_unaligned_u64(ip); ip += sizeof(uint64_t); #if YR_PARANOID_EXEC ensure_within_mem(r1.i); #endif mem[r1.i].i++; break; case OP_PUSH_M: YR_DEBUG_FPRINTF(2, stderr, "- case OP_PUSH_M: // %s()\n", __FUNCTION__); r1.i = yr_unaligned_u64(ip); ip += sizeof(uint64_t); #if YR_PARANOID_EXEC ensure_within_mem(r1.i); #endif r1 = mem[r1.i]; push(r1); break; case OP_POP_M: YR_DEBUG_FPRINTF(2, stderr, "- case OP_POP_M: // %s()\n", __FUNCTION__); r1.i = yr_unaligned_u64(ip); ip += sizeof(uint64_t); #if YR_PARANOID_EXEC ensure_within_mem(r1.i); #endif pop(r2); mem[r1.i] = r2; break; case OP_SET_M: YR_DEBUG_FPRINTF(2, stderr, "- case OP_SET_M: // %s()\n", __FUNCTION__); r1.i = yr_unaligned_u64(ip); ip += sizeof(uint64_t); #if YR_PARANOID_EXEC ensure_within_mem(r1.i); #endif pop(r2); push(r2); if (!is_undef(r2)) mem[r1.i] = r2; break; case OP_SWAPUNDEF: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_SWAPUNDEF: // %s()\n", __FUNCTION__); r1.i = yr_unaligned_u64(ip); ip += sizeof(uint64_t); #if YR_PARANOID_EXEC ensure_within_mem(r1.i); #endif pop(r2); if (is_undef(r2)) { r1 = mem[r1.i]; push(r1); } else { push(r2); } break; case OP_JNUNDEF: // Jump if the top the stack is not undefined without modifying the stack. YR_DEBUG_FPRINTF(2, stderr, "- case OP_JNUNDEF: // %s()\n", __FUNCTION__); pop(r1); push(r1); ip = jmp_if(!is_undef(r1), ip); break; case OP_JUNDEF_P: // Removes a value from the top of the stack and jump if the value is not // undefined. YR_DEBUG_FPRINTF( 2, stderr, "- case OP_JUNDEF_P: // %s()\n", __FUNCTION__); pop(r1); ip = jmp_if(is_undef(r1), ip); break; case OP_JL_P: // Pops two values A and B from the stack and jump if A < B. B is popped // first, and then A. YR_DEBUG_FPRINTF(2, stderr, "- case OP_JL_P: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ip = jmp_if(r1.i < r2.i, ip); break; case OP_JLE_P: // Pops two values A and B from the stack and jump if A <= B. B is popped // first, and then A. YR_DEBUG_FPRINTF(2, stderr, "- case OP_JLE_P: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ip = jmp_if(r1.i <= r2.i, ip); break; case OP_JTRUE: // Jump if the top of the stack is true without modifying the stack. If // the top of the stack is undefined the jump is not taken. YR_DEBUG_FPRINTF(2, stderr, "- case OP_JTRUE: // %s()\n", __FUNCTION__); pop(r1); push(r1); ip = jmp_if(!is_undef(r1) && r1.i, ip); break; case OP_JTRUE_P: // Removes a value from the stack and jump if it is true. If the value // is undefined the jump is not taken. YR_DEBUG_FPRINTF(2, stderr, "- case OP_JTRUE_P: // %s()\n", __FUNCTION__); pop(r1); ip = jmp_if(!is_undef(r1) && r1.i, ip); break; case OP_JFALSE: // Jump if the top of the stack is false without modifying the stack. If // the top of the stack is undefined the jump is not taken. YR_DEBUG_FPRINTF(2, stderr, "- case OP_JFALSE: // %s()\n", __FUNCTION__); pop(r1); push(r1); ip = jmp_if(!is_undef(r1) && !r1.i, ip); break; case OP_JFALSE_P: // Removes a value from the stack and jump if it is false. If the value // is undefined the jump is not taken. YR_DEBUG_FPRINTF( 2, stderr, "- case OP_JFALSE_P: // %s()\n", __FUNCTION__); pop(r1); ip = jmp_if(!is_undef(r1) && !r1.i, ip); break; case OP_JZ: // Jump if the value at the top of the stack is 0 without modifying the // stack. YR_DEBUG_FPRINTF(2, stderr, "- case OP_JZ: // %s()\n", __FUNCTION__); pop(r1); push(r1); ip = jmp_if(r1.i == 0, ip); break; case OP_JZ_P: // Removes a value from the stack and jump if the value is 0. YR_DEBUG_FPRINTF(2, stderr, "- case OP_JZ_P: // %s()\n", __FUNCTION__); pop(r1); ip = jmp_if(r1.i == 0, ip); break; case OP_AND: YR_DEBUG_FPRINTF(2, stderr, "- case OP_AND: // %s()\n", __FUNCTION__); pop(r2); pop(r1); if (is_undef(r1)) r1.i = 0; if (is_undef(r2)) r2.i = 0; r1.i = r1.i && r2.i; push(r1); break; case OP_OR: YR_DEBUG_FPRINTF(2, stderr, "- case OP_OR: // %s()\n", __FUNCTION__); pop(r2); pop(r1); if (is_undef(r1)) r1.i = 0; if (is_undef(r2)) r2.i = 0; r1.i = r1.i || r2.i; push(r1); break; case OP_NOT: YR_DEBUG_FPRINTF(2, stderr, "- case OP_NOT: // %s()\n", __FUNCTION__); pop(r1); if (is_undef(r1)) r1.i = YR_UNDEFINED; else r1.i = !r1.i; push(r1); break; case OP_DEFINED: pop(r1); r1.i = !is_undef(r1); push(r1); break; case OP_MOD: YR_DEBUG_FPRINTF(2, stderr, "- case OP_MOD: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); // If divisor is zero the result is undefined. It's also undefined // when dividing INT64_MIN by -1. if (r2.i == 0 || (r1.i == INT64_MIN && r2.i == -1)) r1.i = YR_UNDEFINED; else r1.i = r1.i % r2.i; push(r1); break; case OP_SHR: YR_DEBUG_FPRINTF(2, stderr, "- case OP_SHR: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); if (r2.i < 0) r1.i = YR_UNDEFINED; else if (r2.i < 64) r1.i = r1.i >> r2.i; else r1.i = 0; push(r1); break; case OP_SHL: YR_DEBUG_FPRINTF(2, stderr, "- case OP_SHL: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); if (r2.i < 0) r1.i = YR_UNDEFINED; else if (r2.i < 64) r1.i = r1.i << r2.i; else r1.i = 0; push(r1); break; case OP_BITWISE_NOT: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_BITWISE_NOT: // %s()\n", __FUNCTION__); pop(r1); ensure_defined(r1); r1.i = ~r1.i; push(r1); break; case OP_BITWISE_AND: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_BITWISE_AND: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.i = r1.i & r2.i; push(r1); break; case OP_BITWISE_OR: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_BITWISE_OR: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.i = r1.i | r2.i; push(r1); break; case OP_BITWISE_XOR: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_BITWISE_XOR: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.i = r1.i ^ r2.i; push(r1); break; case OP_PUSH_RULE: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_PUSH_RULE: // %s()\n", __FUNCTION__); r1.i = yr_unaligned_u64(ip); ip += sizeof(uint64_t); rule = &context->rules->rules_table[r1.i]; if (RULE_IS_DISABLED(rule)) { r2.i = YR_UNDEFINED; } else { if (yr_bitmask_is_set(context->rule_matches_flags, r1.i)) r2.i = 1; else r2.i = 0; } push(r2); break; case OP_INIT_RULE: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_INIT_RULE: // %s()\n", __FUNCTION__); // After the opcode there's an int32_t corresponding to the jump's // offset and an uint32_t corresponding to the rule's index. current_rule_idx = yr_unaligned_u32(ip + sizeof(int32_t)); // The curent rule index can't be larger than the number of rules. assert(current_rule_idx < context->rules->num_rules); current_rule = &context->rules->rules_table[current_rule_idx]; // If the rule is disabled, let's skip its code. bool skip_rule = RULE_IS_DISABLED(current_rule); // The rule is also skipped if it is not required to be evaluated. skip_rule |= yr_bitmask_is_not_set( context->required_eval, current_rule_idx); ip = jmp_if(skip_rule, ip); if (skip_rule) { // If the rule is skipped it is false, and if a global rule is false // we must mark its namespace as unsatisfied. if (RULE_IS_GLOBAL(current_rule)) yr_bitmask_set(context->ns_unsatisfied_flags, current_rule->ns->idx); } else { // If not taking the jump, skip the bytes corresponding to the // rule's index. ip += sizeof(uint32_t); } break; case OP_MATCH_RULE: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_MATCH_RULE: // %s()\n", __FUNCTION__); pop(r1); r2.i = yr_unaligned_u64(ip); ip += sizeof(uint64_t); rule = &context->rules->rules_table[r2.i]; #if YR_PARANOID_EXEC ensure_within_rules_arena(rule); #endif if (!is_undef(r1) && r1.i) yr_bitmask_set(context->rule_matches_flags, r2.i); else if (RULE_IS_GLOBAL(rule)) yr_bitmask_set(context->ns_unsatisfied_flags, rule->ns->idx); #ifdef YR_PROFILING_ENABLED elapsed_time = yr_stopwatch_elapsed_ns(&context->stopwatch); context->profiling_info[r2.i].exec_time += (elapsed_time - start_time); start_time = elapsed_time; #endif assert(stack.sp == 0); // at this point the stack should be empty. break; case OP_OBJ_LOAD: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_OBJ_LOAD: // %s()\n", __FUNCTION__); identifier = yr_unaligned_char_ptr(ip); ip += sizeof(uint64_t); #if YR_PARANOID_EXEC ensure_within_rules_arena(identifier); #endif r1.o = (YR_OBJECT*) yr_hash_table_lookup( context->objects_table, identifier, NULL); assert(r1.o != NULL); push(r1); break; case OP_OBJ_FIELD: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_OBJ_FIELD: // %s()\n", __FUNCTION__); identifier = yr_unaligned_char_ptr(ip); ip += sizeof(uint64_t); #if YR_PARANOID_EXEC ensure_within_rules_arena(identifier); #endif pop(r1); ensure_defined(r1); r1.o = yr_object_lookup_field(r1.o, identifier); if (r1.o == NULL) { result = ERROR_INVALID_FIELD_NAME; stop = true; break; } push(r1); break; case OP_OBJ_VALUE: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_OBJ_VALUE: // %s()\n", __FUNCTION__); pop(r1); ensure_defined(r1); #if YR_PARANOID_EXEC check_object_canary(r1.o); #endif switch (r1.o->type) { case OBJECT_TYPE_INTEGER: r1.i = r1.o->value.i; break; case OBJECT_TYPE_FLOAT: if (yr_isnan(r1.o->value.d)) r1.i = YR_UNDEFINED; else r1.d = r1.o->value.d; break; case OBJECT_TYPE_STRING: if (r1.o->value.ss == NULL) r1.i = YR_UNDEFINED; else r1.ss = r1.o->value.ss; break; default: assert(false); } push(r1); break; case OP_INDEX_ARRAY: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_INDEX_ARRAY: // %s()\n", __FUNCTION__); pop(r1); // index pop(r2); // array ensure_defined(r1); ensure_defined(r2); assert(r2.o->type == OBJECT_TYPE_ARRAY); #if YR_PARANOID_EXEC check_object_canary(r2.o); #endif r1.o = yr_object_array_get_item(r2.o, 0, (int) r1.i); if (r1.o == NULL) r1.i = YR_UNDEFINED; push(r1); break; case OP_LOOKUP_DICT: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_LOOKUP_DICT: // %s()\n", __FUNCTION__); pop(r1); // key pop(r2); // dictionary ensure_defined(r1); ensure_defined(r2); assert(r2.o->type == OBJECT_TYPE_DICTIONARY); #if YR_PARANOID_EXEC check_object_canary(r2.o); #endif r1.o = yr_object_dict_get_item(r2.o, 0, r1.ss->c_string); if (r1.o == NULL) r1.i = YR_UNDEFINED; push(r1); break; case OP_CALL: YR_DEBUG_FPRINTF(2, stderr, "- case OP_CALL: // %s()\n", __FUNCTION__); args_fmt = yr_unaligned_char_ptr(ip); ip += sizeof(uint64_t); int i = (int) strlen(args_fmt); count = 0; #if YR_PARANOID_EXEC if (i > YR_MAX_FUNCTION_ARGS) { stop = true; result = ERROR_INTERNAL_FATAL_ERROR; break; } #endif // pop arguments from stack and copy them to args array while (i > 0) { pop(r1); if (is_undef(r1)) // count the number of undefined args count++; args[i - 1] = r1; i--; } pop(r2); ensure_defined(r2); #if YR_PARANOID_EXEC check_object_canary(r2.o); #endif if (count > 0) { // If there are undefined args, result for function call // is undefined as well. r1.i = YR_UNDEFINED; push(r1); break; } function = object_as_function(r2.o); result = ERROR_INTERNAL_FATAL_ERROR; for (i = 0; i < YR_MAX_OVERLOADED_FUNCTIONS; i++) { if (function->prototypes[i].arguments_fmt == NULL) break; if (strcmp(function->prototypes[i].arguments_fmt, args_fmt) == 0) { result = function->prototypes[i].code(args, context, function); break; } } // If i == YR_MAX_OVERLOADED_FUNCTIONS at this point no matching // prototype was found, but this shouldn't happen. assert(i < YR_MAX_OVERLOADED_FUNCTIONS); // Make a copy of the returned object and push the copy into the stack, // function->return_obj can't be pushed because it can change in // subsequent calls to the same function. if (result == ERROR_SUCCESS) result = yr_object_copy(function->return_obj, &r1.o); // A pointer to the copied object is stored in a arena in order to // free the object before exiting yr_execute_code, obj_count tracks // the number of objects written. if (result == ERROR_SUCCESS) { result = yr_arena_write_data(obj_arena, 0, &r1.o, sizeof(r1.o), NULL); obj_count++; } else { r1.i = YR_UNDEFINED; } stop = (result != ERROR_SUCCESS); push(r1); break; case OP_FOUND: pop(r1); r2.i = context->matches[r1.s->idx].tail != NULL ? 1 : 0; YR_DEBUG_FPRINTF( 2, stderr, "- case OP_FOUND: r2.i=%" PRId64 " // %s()\n", r2.i, __FUNCTION__); push(r2); break; case OP_FOUND_AT: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_FOUND_AT: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r1); #if YR_PARANOID_EXEC ensure_within_rules_arena(r2.p); #endif match = context->matches[r2.s->idx].head; r3.i = false; while (match != NULL) { if (r1.i == match->base + match->offset) { r3.i = true; break; } if (r1.i < match->base + match->offset) break; match = match->next; } push(r3); break; case OP_FOUND_IN: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_FOUND_IN: // %s()\n", __FUNCTION__); pop(r3); pop(r2); pop(r1); ensure_defined(r1); ensure_defined(r2); #if YR_PARANOID_EXEC ensure_within_rules_arena(r3.p); #endif match = context->matches[r3.s->idx].head; r4.i = false; while (match != NULL && !r4.i) { if (match->base + match->offset >= r1.i && match->base + match->offset <= r2.i) { r4.i = true; } if (match->base + match->offset > r2.i) break; match = match->next; } push(r4); break; case OP_COUNT: YR_DEBUG_FPRINTF(2, stderr, "- case OP_COUNT: // %s()\n", __FUNCTION__); pop(r1); #if YR_PARANOID_EXEC ensure_within_rules_arena(r1.p); #endif r2.i = context->matches[r1.s->idx].count; push(r2); break; case OP_COUNT_IN: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_COUNT_IN: // %s()\n", __FUNCTION__); pop(r3); pop(r2); pop(r1); ensure_defined(r1); ensure_defined(r2); #if YR_PARANOID_EXEC ensure_within_rules_arena(r3.p); #endif match = context->matches[r3.s->idx].head; r4.i = 0; while (match != NULL) { if (match->base + match->offset >= r1.i && match->base + match->offset <= r2.i) { r4.i++; } if (match->base + match->offset > r2.i) break; match = match->next; } push(r4); break; case OP_OFFSET: YR_DEBUG_FPRINTF(2, stderr, "- case OP_OFFSET: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r1); #if YR_PARANOID_EXEC ensure_within_rules_arena(r2.p); #endif match = context->matches[r2.s->idx].head; i = 1; r3.i = YR_UNDEFINED; while (match != NULL && r3.i == YR_UNDEFINED) { if (r1.i == i) r3.i = match->base + match->offset; i++; match = match->next; } push(r3); break; case OP_LENGTH: YR_DEBUG_FPRINTF(2, stderr, "- case OP_LENGTH: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r1); #if YR_PARANOID_EXEC ensure_within_rules_arena(r2.p); #endif match = context->matches[r2.s->idx].head; i = 1; r3.i = YR_UNDEFINED; while (match != NULL && r3.i == YR_UNDEFINED) { if (r1.i == i) r3.i = match->match_length; i++; match = match->next; } push(r3); break; case OP_OF: case OP_OF_PERCENT: r2.i = yr_unaligned_u64(ip); ip += sizeof(uint64_t); assert(r2.i == OF_STRING_SET || r2.i == OF_RULE_SET); found = 0; count = 0; pop(r1); while (!is_undef(r1)) { if (r2.i == OF_STRING_SET) { if (context->matches[r1.s->idx].tail != NULL) { found++; } } else { // r1.i is 1 if the rule has already matched and zero otherwise. found += r1.i; } count++; pop(r1); } pop(r2); if (opcode == OP_OF) { YR_DEBUG_FPRINTF(2, stderr, "- case OP_OF: // %s()\n", __FUNCTION__); // Quantifier is "all" if (is_undef(r2)) { r1.i = found >= count ? 1 : 0; } // Quantifier is 0 or none. This is a special case in which we want // exactly 0 strings matching. More information at: // https://github.com/VirusTotal/yara/issues/1695 else if (r2.i == 0) { r1.i = found == 0 ? 1 : 0; } // In all other cases the number of strings matching should be at // least the amount specified by the quantifier. else { r1.i = found >= r2.i ? 1 : 0; } } else // OP_OF_PERCENT { YR_DEBUG_FPRINTF( 2, stderr, "- case OP_OF_PERCENT: // %s()\n", __FUNCTION__); // If, by some weird reason, we manage to get an undefined string // reference as the first thing on the stack then count would be zero. // I don't know how this could ever happen but better to check for it. if (is_undef(r2) || count == 0) r1.i = YR_UNDEFINED; else r1.i = (((double) found / count) * 100) >= r2.i ? 1 : 0; } push(r1); break; case OP_OF_FOUND_IN: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_OF_FOUND_IN: // %s()\n", __FUNCTION__); found = 0; count = 0; pop(r2); // Offset range end pop(r1); // Offset range start pop(r3); // First string // If any of the range boundaries are undefined the result is also // undefined, be we need to unwind the stack first. if (is_undef(r1) || is_undef(r2)) { // Remove all the strings. while (!is_undef(r3)) pop(r3); // Remove the quantifier at the bottom of the stack. pop(r3); r1.i = YR_UNDEFINED; push(r1); break; } while (!is_undef(r3)) { #if YR_PARANOID_EXEC ensure_within_rules_arena(r3.p); #endif match = context->matches[r3.s->idx].head; while (match != NULL) { // String match within range start and range end? if (match->base + match->offset >= r1.i && match->base + match->offset <= r2.i) { found++; break; } // If current match is past range end, we can stop as matches // are sorted by offset in increasing order, so all remaining // matches are part the range end too. if (match->base + match->offset > r1.i) break; match = match->next; } count++; pop(r3); } pop(r2); // Quantifier X in expressions like "X of string_set in range" // Quantifier is "all". if (is_undef(r2)) { r1.i = found >= count ? 1 : 0; } // Quantifier is 0 or none. This is a special case in which we want // exactly 0 strings matching. More information at: // https://github.com/VirusTotal/yara/issues/1695 else if (r2.i == 0) { r1.i = found == 0 ? 1 : 0; } // In all other cases the number of strings matching should be at least // the amount specified by the quantifier. else { r1.i = found >= r2.i ? 1 : 0; } push(r1); break; case OP_OF_FOUND_AT: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_OF_FOUND_AT: // %s()\n", __FUNCTION__); found = 0; count = 0; pop(r2); // Match location pop(r1); // First string // Match location must be defined. if (is_undef(r2)) { // Remove all the strings. while (!is_undef(r1)) pop(r1); // Remove the quantifier at the bottom of the stack. pop(r1); r1.i = YR_UNDEFINED; push(r1); break; } while (!is_undef(r1)) { #if YR_PARANOID_EXEC ensure_within_rules_arena(r1.p); #endif match = context->matches[r1.s->idx].head; while (match != NULL) { // String match at the desired location? if (match->base + match->offset == r2.i) { found++; break; } // If current match is past desired location, we can stop as matches // are sorted by offset in increasing order, so all remaining // matches are past it. if (match->base + match->offset > r2.i) break; match = match->next; } count++; pop(r1); } pop(r2); // Quantifier X in expressions like "X of string_set in range" // Quantifier is "all". if (is_undef(r2)) { r1.i = found >= count ? 1 : 0; } // Quantifier is 0 or none. This is a special case in which we want // exactly 0 strings matching. More information at: // https://github.com/VirusTotal/yara/issues/1695 else if (r2.i == 0) { r1.i = found == 0 ? 1 : 0; } // In all other cases the number of strings matching should be at least // the amount specified by the quantifier. else { r1.i = found >= r2.i ? 1 : 0; } push(r1); break; case OP_FILESIZE: r1.i = context->file_size; YR_DEBUG_FPRINTF( 2, stderr, "- case OP_FILESIZE: r1.i=%" PRId64 "%s // %s()\n", r1.i, r1.i == YR_UNDEFINED ? " AKA YR_UNDEFINED" : "", __FUNCTION__); push(r1); break; case OP_ENTRYPOINT: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_ENTRYPOINT: // %s()\n", __FUNCTION__); r1.i = context->entry_point; push(r1); break; case OP_INT8: YR_DEBUG_FPRINTF(2, stderr, "- case OP_INT8: // %s()\n", __FUNCTION__); pop(r1); r1.i = read_int8_t_little_endian(context->iterator, (size_t) r1.i); push(r1); break; case OP_INT16: YR_DEBUG_FPRINTF(2, stderr, "- case OP_INT16: // %s()\n", __FUNCTION__); pop(r1); r1.i = read_int16_t_little_endian(context->iterator, (size_t) r1.i); push(r1); break; case OP_INT32: YR_DEBUG_FPRINTF(2, stderr, "- case OP_INT32: // %s()\n", __FUNCTION__); pop(r1); r1.i = read_int32_t_little_endian(context->iterator, (size_t) r1.i); push(r1); break; case OP_UINT8: YR_DEBUG_FPRINTF(2, stderr, "- case OP_UINT8: // %s()\n", __FUNCTION__); pop(r1); r1.i = read_uint8_t_little_endian(context->iterator, (size_t) r1.i); push(r1); break; case OP_UINT16: YR_DEBUG_FPRINTF(2, stderr, "- case OP_UINT16: // %s()\n", __FUNCTION__); pop(r1); r1.i = read_uint16_t_little_endian(context->iterator, (size_t) r1.i); push(r1); break; case OP_UINT32: YR_DEBUG_FPRINTF(2, stderr, "- case OP_UINT32: // %s()\n", __FUNCTION__); pop(r1); r1.i = read_uint32_t_little_endian(context->iterator, (size_t) r1.i); push(r1); break; case OP_INT8BE: YR_DEBUG_FPRINTF(2, stderr, "- case OP_INT8BE: // %s()\n", __FUNCTION__); pop(r1); r1.i = read_int8_t_big_endian(context->iterator, (size_t) r1.i); push(r1); break; case OP_INT16BE: YR_DEBUG_FPRINTF(2, stderr, "- case OP_INT16BE: // %s()\n", __FUNCTION__); pop(r1); r1.i = read_int16_t_big_endian(context->iterator, (size_t) r1.i); push(r1); break; case OP_INT32BE: YR_DEBUG_FPRINTF(2, stderr, "- case OP_INT32BE: // %s()\n", __FUNCTION__); pop(r1); r1.i = read_int32_t_big_endian(context->iterator, (size_t) r1.i); push(r1); break; case OP_UINT8BE: YR_DEBUG_FPRINTF(2, stderr, "- case OP_UINT8BE: // %s()\n", __FUNCTION__); pop(r1); r1.i = read_uint8_t_big_endian(context->iterator, (size_t) r1.i); push(r1); break; case OP_UINT16BE: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_UINT16BE: // %s()\n", __FUNCTION__); pop(r1); r1.i = read_uint16_t_big_endian(context->iterator, (size_t) r1.i); push(r1); break; case OP_UINT32BE: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_UINT32BE: // %s()\n", __FUNCTION__); pop(r1); r1.i = read_uint32_t_big_endian(context->iterator, (size_t) r1.i); push(r1); break; case OP_IMPORT: YR_DEBUG_FPRINTF(2, stderr, "- case OP_IMPORT: // %s()\n", __FUNCTION__); r1.i = yr_unaligned_u64(ip); ip += sizeof(uint64_t); #if YR_PARANOID_EXEC ensure_within_rules_arena(r1.p); #endif result = yr_modules_load((char*) r1.p, context); if (result != ERROR_SUCCESS) stop = true; break; case OP_MATCHES: YR_DEBUG_FPRINTF(2, stderr, "- case OP_MATCHES: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); result = yr_re_exec( context, (uint8_t*) r2.re->code, (uint8_t*) r1.ss->c_string, r1.ss->length, 0, r2.re->flags | RE_FLAGS_SCAN, NULL, NULL, &found); if (result != ERROR_SUCCESS) stop = true; r1.i = found >= 0; push(r1); break; case OP_INT_TO_DBL: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_INT_TO_DBL: // %s()\n", __FUNCTION__); r1.i = yr_unaligned_u64(ip); ip += sizeof(uint64_t); #if YR_PARANOID_EXEC if (r1.i > stack.sp || stack.sp - r1.i >= stack.capacity) { stop = true; result = ERROR_INTERNAL_FATAL_ERROR; break; } #endif r2 = stack.items[stack.sp - r1.i]; if (is_undef(r2)) stack.items[stack.sp - r1.i].i = YR_UNDEFINED; else stack.items[stack.sp - r1.i].d = (double) r2.i; break; case OP_STR_TO_BOOL: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_STR_TO_BOOL: // %s()\n", __FUNCTION__); pop(r1); ensure_defined(r1); r1.i = r1.ss->length > 0; push(r1); break; case OP_INT_EQ: YR_DEBUG_FPRINTF(2, stderr, "- case OP_INT_EQ: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.i = r1.i == r2.i; push(r1); break; case OP_INT_NEQ: YR_DEBUG_FPRINTF(2, stderr, "- case OP_INT_NEQ: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.i = r1.i != r2.i; push(r1); break; case OP_INT_LT: YR_DEBUG_FPRINTF(2, stderr, "- case OP_INT_LT: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.i = r1.i < r2.i; push(r1); break; case OP_INT_GT: YR_DEBUG_FPRINTF(2, stderr, "- case OP_INT_GT: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.i = r1.i > r2.i; push(r1); break; case OP_INT_LE: YR_DEBUG_FPRINTF(2, stderr, "- case OP_INT_LE: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.i = r1.i <= r2.i; push(r1); break; case OP_INT_GE: YR_DEBUG_FPRINTF(2, stderr, "- case OP_INT_GE: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.i = r1.i >= r2.i; push(r1); break; case OP_INT_ADD: YR_DEBUG_FPRINTF(2, stderr, "- case OP_INT_ADD: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.i = r1.i + r2.i; push(r1); break; case OP_INT_SUB: YR_DEBUG_FPRINTF(2, stderr, "- case OP_INT_SUB: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.i = r1.i - r2.i; push(r1); break; case OP_INT_MUL: YR_DEBUG_FPRINTF(2, stderr, "- case OP_INT_MUL: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.i = r1.i * r2.i; push(r1); break; case OP_INT_DIV: YR_DEBUG_FPRINTF(2, stderr, "- case OP_INT_DIV: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); // If divisor is zero the result is undefined. It's also undefined // when dividing INT64_MIN by -1. if (r2.i == 0 || (r1.i == INT64_MIN && r2.i == -1)) r1.i = YR_UNDEFINED; else r1.i = r1.i / r2.i; push(r1); break; case OP_INT_MINUS: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_INT_MINUS: // %s()\n", __FUNCTION__); pop(r1); ensure_defined(r1); r1.i = -r1.i; push(r1); break; case OP_DBL_LT: YR_DEBUG_FPRINTF(2, stderr, "- case OP_DBL_LT: // %s()\n", __FUNCTION__); pop(r2); pop(r1); if (is_undef(r1) || is_undef(r2)) r1.i = false; else r1.i = r1.d < r2.d; push(r1); break; case OP_DBL_GT: YR_DEBUG_FPRINTF(2, stderr, "- case OP_DBL_GT: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.i = r1.d > r2.d; push(r1); break; case OP_DBL_LE: YR_DEBUG_FPRINTF(2, stderr, "- case OP_DBL_LE: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.i = r1.d <= r2.d; push(r1); break; case OP_DBL_GE: YR_DEBUG_FPRINTF(2, stderr, "- case OP_DBL_GE: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.i = r1.d >= r2.d; push(r1); break; case OP_DBL_EQ: YR_DEBUG_FPRINTF(2, stderr, "- case OP_DBL_EQ: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.i = fabs(r1.d - r2.d) < DBL_EPSILON; push(r1); break; case OP_DBL_NEQ: YR_DEBUG_FPRINTF(2, stderr, "- case OP_DBL_NEQ: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.i = fabs(r1.d - r2.d) >= DBL_EPSILON; push(r1); break; case OP_DBL_ADD: YR_DEBUG_FPRINTF(2, stderr, "- case OP_DBL_ADD: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.d = r1.d + r2.d; push(r1); break; case OP_DBL_SUB: YR_DEBUG_FPRINTF(2, stderr, "- case OP_DBL_SUB: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.d = r1.d - r2.d; push(r1); break; case OP_DBL_MUL: YR_DEBUG_FPRINTF(2, stderr, "- case OP_DBL_MUL: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.d = r1.d * r2.d; push(r1); break; case OP_DBL_DIV: YR_DEBUG_FPRINTF(2, stderr, "- case OP_DBL_DIV: // %s()\n", __FUNCTION__); pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); r1.d = r1.d / r2.d; push(r1); break; case OP_DBL_MINUS: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_DBL_MINUS: // %s()\n", __FUNCTION__); pop(r1); ensure_defined(r1); r1.d = -r1.d; push(r1); break; case OP_STR_EQ: case OP_STR_NEQ: case OP_STR_LT: case OP_STR_LE: case OP_STR_GT: case OP_STR_GE: pop(r2); pop(r1); ensure_defined(r2); ensure_defined(r1); switch (opcode) { case OP_STR_EQ: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_STR_EQ: // %s()\n", __FUNCTION__); r1.i = (ss_compare(r1.ss, r2.ss) == 0); break; case OP_STR_NEQ: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_STR_NEQ: // %s()\n", __FUNCTION__); r1.i = (ss_compare(r1.ss, r2.ss) != 0); break; case OP_STR_LT: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_STR_LT: // %s()\n", __FUNCTION__); r1.i = (ss_compare(r1.ss, r2.ss) < 0); break; case OP_STR_LE: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_STR_LE: // %s()\n", __FUNCTION__); r1.i = (ss_compare(r1.ss, r2.ss) <= 0); break; case OP_STR_GT: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_STR_GT: // %s()\n", __FUNCTION__); r1.i = (ss_compare(r1.ss, r2.ss) > 0); break; case OP_STR_GE: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_STR_GE: // %s()\n", __FUNCTION__); r1.i = (ss_compare(r1.ss, r2.ss) >= 0); break; } push(r1); break; case OP_CONTAINS: case OP_ICONTAINS: case OP_STARTSWITH: case OP_ISTARTSWITH: case OP_ENDSWITH: case OP_IENDSWITH: case OP_IEQUALS: pop(r2); pop(r1); ensure_defined(r1); ensure_defined(r2); switch (opcode) { case OP_CONTAINS: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_CONTAINS: // %s()\n", __FUNCTION__); r1.i = ss_contains(r1.ss, r2.ss); break; case OP_ICONTAINS: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_ICONTAINS: // %s()\n", __FUNCTION__); r1.i = ss_icontains(r1.ss, r2.ss); break; case OP_STARTSWITH: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_STARTSWITH: // %s()\n", __FUNCTION__); r1.i = ss_startswith(r1.ss, r2.ss); break; case OP_ISTARTSWITH: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_ISTARTSWITH: // %s()\n", __FUNCTION__); r1.i = ss_istartswith(r1.ss, r2.ss); break; case OP_ENDSWITH: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_ENDSWITH: // %s()\n", __FUNCTION__); r1.i = ss_endswith(r1.ss, r2.ss); break; case OP_IENDSWITH: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_IENDSWITH: // %s()\n", __FUNCTION__); r1.i = ss_iendswith(r1.ss, r2.ss); break; case OP_IEQUALS: YR_DEBUG_FPRINTF( 2, stderr, "- case OP_IEQUALS: // %s()\n", __FUNCTION__); r1.i = ss_icompare(r1.ss, r2.ss) == 0; break; } push(r1); break; default: YR_DEBUG_FPRINTF( 2, stderr, "- case : // %s()\n", __FUNCTION__); // Unknown instruction, this shouldn't happen. assert(false); } // Check for timeout every 100 instruction cycles. If timeout == 0 it means // no timeout at all. if (context->timeout > 0ULL && ++cycle == 100) { elapsed_time = yr_stopwatch_elapsed_ns(&context->stopwatch); if (elapsed_time > context->timeout) { #ifdef YR_PROFILING_ENABLED context->profiling_info[current_rule_idx].exec_time += (elapsed_time - start_time); #endif result = ERROR_SCAN_TIMEOUT; stop = true; } cycle = 0; } } obj_ptr = yr_arena_get_ptr(obj_arena, 0, 0); for (int i = 0; i < obj_count; i++) yr_object_destroy(obj_ptr[i]); yr_arena_release(obj_arena); yr_notebook_destroy(it_notebook); yr_modules_unload_all(context); yr_free(stack.items); YR_DEBUG_FPRINTF( 2, stderr, "} = %d AKA %s // %s()\n", result, yr_debug_error_as_string(result), __FUNCTION__); return result; } yara-4.5.3/libyara/exefiles.c000066400000000000000000000267741501365277300161030ustar00rootroot00000000000000/* Copyright (c) 2007-2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #ifndef NULL #define NULL 0 #endif #ifndef MIN #define MIN(x, y) ((x < y) ? (x) : (y)) #endif PIMAGE_NT_HEADERS32 yr_get_pe_header( const uint8_t* buffer, size_t buffer_length) { PIMAGE_DOS_HEADER mz_header; PIMAGE_NT_HEADERS32 pe_header; size_t headers_size = 0; if (buffer_length < sizeof(IMAGE_DOS_HEADER)) return NULL; mz_header = (PIMAGE_DOS_HEADER) buffer; if (yr_le16toh(mz_header->e_magic) != IMAGE_DOS_SIGNATURE) return NULL; if ((int32_t) yr_le32toh(mz_header->e_lfanew) < 0) return NULL; headers_size = yr_le32toh(mz_header->e_lfanew) + sizeof(pe_header->Signature) + sizeof(IMAGE_FILE_HEADER); if (buffer_length < headers_size) return NULL; pe_header = (PIMAGE_NT_HEADERS32)(buffer + yr_le32toh(mz_header->e_lfanew)); headers_size += sizeof(IMAGE_OPTIONAL_HEADER32); if (yr_le32toh(pe_header->Signature) == IMAGE_NT_SIGNATURE && (yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_I386 || yr_le16toh(pe_header->FileHeader.Machine) == IMAGE_FILE_MACHINE_AMD64) && buffer_length > headers_size) { return pe_header; } else { return NULL; } } uint64_t yr_pe_rva_to_offset( PIMAGE_NT_HEADERS32 pe_header, uint64_t rva, size_t buffer_length) { int i = 0; PIMAGE_SECTION_HEADER section; DWORD section_rva; DWORD section_offset; section = IMAGE_FIRST_SECTION(pe_header); section_rva = 0; section_offset = 0; while (i < MIN(yr_le16toh(pe_header->FileHeader.NumberOfSections), 60)) { if ((uint8_t*) section - (uint8_t*) pe_header + sizeof(IMAGE_SECTION_HEADER) < buffer_length) { if (rva >= yr_le32toh(section->VirtualAddress) && section_rva <= yr_le32toh(section->VirtualAddress)) { section_rva = yr_le32toh(section->VirtualAddress); section_offset = yr_le32toh(section->PointerToRawData); } section++; i++; } else { return 0; } } return section_offset + (rva - section_rva); } int yr_get_elf_type(const uint8_t* buffer, size_t buffer_length) { elf_ident_t* elf_ident; if (buffer_length < sizeof(elf_ident_t)) return 0; elf_ident = (elf_ident_t*) buffer; if (yr_le32toh(elf_ident->magic) != ELF_MAGIC) { return 0; } switch (elf_ident->_class) { case ELF_CLASS_32: if (buffer_length < sizeof(elf32_header_t)) { return 0; } break; case ELF_CLASS_64: if (buffer_length < sizeof(elf64_header_t)) { return 0; } break; default: /* Unexpected class */ return 0; } return elf_ident->_class; } static uint64_t yr_elf_rva_to_offset_32( elf32_header_t* elf_header, uint64_t rva, size_t buffer_length) { // if the binary is an executable then prefer the program headers to resolve // the offset if (yr_le16toh(elf_header->type) == ELF_ET_EXEC) { int i; elf32_program_header_t* program; if (yr_le32toh(elf_header->ph_offset) == 0 || yr_le16toh(elf_header->ph_entry_count == 0)) return 0; // check to prevent integer wraps if (ULONG_MAX - yr_le16toh(elf_header->ph_entry_count) < sizeof(elf32_program_header_t) * yr_le16toh(elf_header->ph_entry_count)) return 0; // check that 'ph_offset' doesn't wrap when added to the // size of entries. if (ULONG_MAX - yr_le32toh(elf_header->ph_offset) < sizeof(elf32_program_header_t) * yr_le16toh(elf_header->ph_entry_count)) return 0; // ensure we don't exceed the buffer size if (yr_le32toh(elf_header->ph_offset) + sizeof(elf32_program_header_t) * yr_le16toh(elf_header->ph_entry_count) > buffer_length) return 0; program = (elf32_program_header_t*) ((uint8_t*) elf_header + yr_le32toh(elf_header->ph_offset)); for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++) { if (rva >= yr_le32toh(program->virt_addr) && rva < yr_le32toh(program->virt_addr) + yr_le32toh(program->mem_size)) { return yr_le32toh(program->offset) + (rva - yr_le32toh(program->virt_addr)); } program++; } } else { int i; elf32_section_header_t* section; if (yr_le32toh(elf_header->sh_offset) == 0 || yr_le16toh(elf_header->sh_entry_count == 0)) return 0; // check to prevent integer wraps if (ULONG_MAX - yr_le16toh(elf_header->sh_entry_count) < sizeof(elf32_section_header_t) * yr_le16toh(elf_header->sh_entry_count)) return 0; // check that 'sh_offset' doesn't wrap when added to the // size of entries. if (ULONG_MAX - yr_le32toh(elf_header->sh_offset) < sizeof(elf32_section_header_t) * yr_le16toh(elf_header->sh_entry_count)) return 0; if (yr_le32toh(elf_header->sh_offset) + sizeof(elf32_section_header_t) * yr_le16toh(elf_header->sh_entry_count) > buffer_length) return 0; section = (elf32_section_header_t*) ((unsigned char*) elf_header + yr_le32toh(elf_header->sh_offset)); for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++) { if (yr_le32toh(section->type) != ELF_SHT_NULL && yr_le32toh(section->type) != ELF_SHT_NOBITS && rva >= yr_le32toh(section->addr) && rva < yr_le32toh(section->addr) + yr_le32toh(section->size)) { // prevent integer wrapping with the return value if (ULONG_MAX - yr_le32toh(section->offset) < (rva - yr_le32toh(section->addr))) return 0; else return yr_le32toh(section->offset) + (rva - yr_le32toh(section->addr)); } section++; } } return 0; } static uint64_t yr_elf_rva_to_offset_64( elf64_header_t* elf_header, uint64_t rva, size_t buffer_length) { // if the binary is an executable then prefer the program headers to resolve // the offset if (yr_le16toh(elf_header->type) == ELF_ET_EXEC) { int i; elf64_program_header_t* program; if (yr_le64toh(elf_header->ph_offset) == 0 || yr_le16toh(elf_header->ph_entry_count == 0)) return 0; // check that 'ph_offset' doesn't wrap when added to the // size of entries. if (ULONG_MAX - yr_le64toh(elf_header->ph_offset) < sizeof(elf64_program_header_t) * yr_le16toh(elf_header->ph_entry_count)) return 0; // ensure we don't exceed the buffer size if (yr_le64toh(elf_header->ph_offset) + sizeof(elf64_program_header_t) * yr_le16toh(elf_header->ph_entry_count) > buffer_length) return 0; program = (elf64_program_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->ph_offset)); for (i = 0; i < yr_le16toh(elf_header->ph_entry_count); i++) { if (rva >= yr_le64toh(program->virt_addr) && rva < yr_le64toh(program->virt_addr) + yr_le64toh(program->mem_size)) { return yr_le64toh(program->offset) + (rva - yr_le64toh(program->virt_addr)); } program++; } } else { int i; elf64_section_header_t* section; if (yr_le64toh(elf_header->sh_offset) == 0 || yr_le16toh(elf_header->sh_entry_count) == 0) return 0; // check that 'sh_offset' doesn't wrap when added to the // size of entries. if (ULONG_MAX - yr_le64toh(elf_header->sh_offset) < sizeof(elf64_section_header_t) * yr_le16toh(elf_header->sh_entry_count)) return 0; if (yr_le64toh(elf_header->sh_offset) + sizeof(elf64_section_header_t) * yr_le16toh(elf_header->sh_entry_count) > buffer_length) return 0; section = (elf64_section_header_t*) ((uint8_t*) elf_header + yr_le64toh(elf_header->sh_offset)); for (i = 0; i < yr_le16toh(elf_header->sh_entry_count); i++) { if (yr_le32toh(section->type) != ELF_SHT_NULL && yr_le32toh(section->type) != ELF_SHT_NOBITS && rva >= yr_le64toh(section->addr) && rva < yr_le64toh(section->addr) + yr_le64toh(section->size)) { return yr_le64toh(section->offset) + (rva - yr_le64toh(section->addr)); } section++; } } return 0; } uint64_t yr_get_entry_point_offset(const uint8_t* buffer, size_t buffer_length) { PIMAGE_NT_HEADERS32 pe_header; elf32_header_t* elf_header32; elf64_header_t* elf_header64; pe_header = yr_get_pe_header(buffer, buffer_length); if (pe_header != NULL) { return yr_pe_rva_to_offset( pe_header, yr_le32toh(pe_header->OptionalHeader.AddressOfEntryPoint), buffer_length - ((uint8_t*) pe_header - buffer)); } switch (yr_get_elf_type(buffer, buffer_length)) { case ELF_CLASS_32: elf_header32 = (elf32_header_t*) buffer; return yr_elf_rva_to_offset_32( elf_header32, yr_le32toh(elf_header32->entry), buffer_length); case ELF_CLASS_64: elf_header64 = (elf64_header_t*) buffer; return yr_elf_rva_to_offset_64( elf_header64, yr_le64toh(elf_header64->entry), buffer_length); } return YR_UNDEFINED; } uint64_t yr_get_entry_point_address( const uint8_t* buffer, size_t buffer_length, uint64_t base_address) { PIMAGE_NT_HEADERS32 pe_header; elf32_header_t* elf_header32; elf64_header_t* elf_header64; pe_header = yr_get_pe_header(buffer, buffer_length); // If file is PE but not a DLL. if (pe_header != NULL && !(pe_header->FileHeader.Characteristics & IMAGE_FILE_DLL)) return base_address + pe_header->OptionalHeader.AddressOfEntryPoint; // If file is executable ELF, not shared library. switch (yr_get_elf_type(buffer, buffer_length)) { case ELF_CLASS_32: elf_header32 = (elf32_header_t*) buffer; if (elf_header32->type == ELF_ET_EXEC) return base_address + elf_header32->entry; break; case ELF_CLASS_64: elf_header64 = (elf64_header_t*) buffer; if (elf_header64->type == ELF_ET_EXEC) return base_address + elf_header64->entry; break; } return YR_UNDEFINED; } yara-4.5.3/libyara/filemap.c000066400000000000000000000243171501365277300157030ustar00rootroot00000000000000/* Copyright (c) 2007-2015. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #if defined(_WIN32) || defined(__CYGWIN__) #include #else #include #include #include #endif #include #include //////////////////////////////////////////////////////////////////////////////// // Maps a whole file into memory. // // Args: // file_path: Path of the file to map. // pmapped_file: Pointer to a YR_MAPPED_FILE that will be filled with // information about the mapping. // Returns: // ERROR_SUCCESS // ERROR_INVALID_ARGUMENT // ERROR_COULD_NOT_OPEN_FILE // ERROR_COULD_NOT_MAP_FILE // YR_API int yr_filemap_map(const char* file_path, YR_MAPPED_FILE* pmapped_file) { return yr_filemap_map_ex(file_path, 0, 0, pmapped_file); } //////////////////////////////////////////////////////////////////////////////// // Maps a portion of a file (specified by descriptor) into memory. // // Args: // file: File descriptor representing the file to map. // offset: File offset where the mapping will begin. This offset must be // multiple of 1MB and not greater than the actual file size. // size: Number of bytes that will be mapped. If zero or greater than the // actual file size all content until the end of the file will be // mapped. // pmapped_file: Pointer to a YR_MAPPED_FILE struct that will be filled with // the new mapping. // Returns: // ERROR_SUCCESS // ERROR_INVALID_ARGUMENT // ERROR_COULD_NOT_OPEN_FILE // ERROR_COULD_NOT_MAP_FILE // #if defined(_WIN32) || defined(__CYGWIN__) YR_API int yr_filemap_map_fd( YR_FILE_DESCRIPTOR file, uint64_t offset, size_t size, YR_MAPPED_FILE* pmapped_file) { LARGE_INTEGER fs; size_t file_size; pmapped_file->file = file; pmapped_file->mapping = NULL; pmapped_file->data = NULL; pmapped_file->size = 0; // Ensure that offset is aligned to 1MB if (offset >> 20 << 20 != offset) return ERROR_INVALID_ARGUMENT; if (GetFileSizeEx(pmapped_file->file, &fs)) { #ifdef _WIN64 file_size = fs.QuadPart; #else file_size = fs.LowPart; #endif } else { pmapped_file->file = INVALID_HANDLE_VALUE; return ERROR_COULD_NOT_OPEN_FILE; } if (offset > (uint64_t) file_size) return ERROR_COULD_NOT_MAP_FILE; if (size == 0) size = (size_t)(file_size - offset); pmapped_file->size = yr_min(size, (size_t)(file_size - offset)); if (pmapped_file->size != 0) { pmapped_file->mapping = CreateFileMapping( pmapped_file->file, NULL, PAGE_READONLY, 0, 0, NULL); if (pmapped_file->mapping == NULL) { pmapped_file->file = INVALID_HANDLE_VALUE; pmapped_file->size = 0; return ERROR_COULD_NOT_MAP_FILE; } pmapped_file->data = (const uint8_t*) MapViewOfFile( pmapped_file->mapping, FILE_MAP_READ, offset >> 32, offset & 0xFFFFFFFF, pmapped_file->size); if (pmapped_file->data == NULL) { CloseHandle(pmapped_file->mapping); pmapped_file->mapping = NULL; pmapped_file->file = INVALID_HANDLE_VALUE; pmapped_file->size = 0; return ERROR_COULD_NOT_MAP_FILE; } } else { pmapped_file->mapping = NULL; pmapped_file->data = NULL; } return ERROR_SUCCESS; } #else // POSIX #ifdef __linux__ #include // This constant can be found in linux/magic.h and the statfs(2) manpage. // // We don't want to include linux/magic.h here because it may not be // available in cross-build environments, see // https://github.com/Hugal31/yara-rust/issues/115 #define PROC_SUPER_MAGIC 0x9fa0 #endif #define MAP_EXTRA_FLAGS 0 #if defined(__APPLE__) // MacOS defines some extra flags for mmap.The MAP_RESILIENT_CODESIGN allows // to read from binaries whose code signature is invalid, without this flags // any attempt to read from such binaries causes a crash, see: // https://github.com/VirusTotal/yara/issues/1309. // // Also, reading from files in removable media that becomes unavailable // crashes the program if the MAP_RESILIENT_MEDIA flag is not set. #if defined(MAP_RESILIENT_CODESIGN) #undef MAP_EXTRA_FLAGS #if defined(MAP_RESILIENT_MEDIA) #define MAP_EXTRA_FLAGS MAP_RESILIENT_CODESIGN | MAP_RESILIENT_MEDIA #else #define MAP_EXTRA_FLAGS MAP_RESILIENT_CODESIGN #endif #endif // #if defined(MAP_RESILIENT_CODESIGN) #endif // #if defined (__APPLE__) YR_API int yr_filemap_map_fd( YR_FILE_DESCRIPTOR file, uint64_t offset, size_t size, YR_MAPPED_FILE* pmapped_file) { struct stat st; #ifdef __linux__ struct statfs stfs; #endif pmapped_file->file = file; pmapped_file->data = NULL; pmapped_file->size = 0; // Ensure that offset is aligned to 1MB if (offset >> 20 << 20 != offset) return ERROR_INVALID_ARGUMENT; if (fstat(file, &st) != 0 || S_ISDIR(st.st_mode)) return ERROR_COULD_NOT_OPEN_FILE; if (offset > st.st_size) return ERROR_COULD_NOT_MAP_FILE; #ifdef __linux__ if (fstatfs(file, &stfs) != 0) return ERROR_COULD_NOT_OPEN_FILE; switch (stfs.f_type) { case PROC_SUPER_MAGIC: return ERROR_COULD_NOT_OPEN_FILE; } #endif if (size == 0) size = (size_t)(st.st_size - offset); pmapped_file->size = yr_min(size, (size_t)(st.st_size - offset)); if (pmapped_file->size != 0) { pmapped_file->data = (const uint8_t*) mmap( 0, pmapped_file->size, PROT_READ, MAP_PRIVATE | MAP_EXTRA_FLAGS, pmapped_file->file, offset); if (pmapped_file->data == MAP_FAILED) { pmapped_file->data = NULL; pmapped_file->size = 0; pmapped_file->file = -1; return ERROR_COULD_NOT_MAP_FILE; } madvise((void*) pmapped_file->data, pmapped_file->size, MADV_SEQUENTIAL); } else { pmapped_file->data = NULL; } return ERROR_SUCCESS; } #endif //////////////////////////////////////////////////////////////////////////////// // Maps a portion of a file (specified by path) into memory. // // Args: // file_path: Path of the file to map. // offset: File offset where the mapping will begin. This offset must be // multiple of 1MB and not greater than the actual file size. // size: Number of bytes that will be mapped. If zero or greater than the // actual file size all content until the end of the file will be // mapped. // pmapped_file: Pointer to a YR_MAPPED_FILE struct that will be filled with // the new mapping. // Returns: // ERROR_SUCCESS // ERROR_INVALID_ARGUMENT // ERROR_COULD_NOT_OPEN_FILE // ERROR_COULD_NOT_MAP_FILE // #if defined(_WIN32) || defined(__CYGWIN__) YR_API int yr_filemap_map_ex( const char* file_path, uint64_t offset, size_t size, YR_MAPPED_FILE* pmapped_file) { YR_FILE_DESCRIPTOR fd; int result; if (file_path == NULL) return ERROR_INVALID_ARGUMENT; fd = CreateFileA( file_path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (fd == INVALID_HANDLE_VALUE) return ERROR_COULD_NOT_OPEN_FILE; result = yr_filemap_map_fd(fd, offset, size, pmapped_file); if (result != ERROR_SUCCESS) CloseHandle(fd); return result; } #else // POSIX YR_API int yr_filemap_map_ex( const char* file_path, uint64_t offset, size_t size, YR_MAPPED_FILE* pmapped_file) { YR_FILE_DESCRIPTOR fd; int result; if (file_path == NULL) return ERROR_INVALID_ARGUMENT; fd = open(file_path, O_RDONLY); if (fd == -1) return ERROR_COULD_NOT_OPEN_FILE; result = yr_filemap_map_fd(fd, offset, size, pmapped_file); if (result != ERROR_SUCCESS) close(fd); return result; } #endif //////////////////////////////////////////////////////////////////////////////// // Unmaps a file mapping. // // Args: // pmapped_file: Pointer to a YR_MAPPED_FILE that struct. // #ifdef WIN32 YR_API void yr_filemap_unmap_fd(YR_MAPPED_FILE* pmapped_file) { if (pmapped_file->data != NULL) UnmapViewOfFile(pmapped_file->data); if (pmapped_file->mapping != NULL) CloseHandle(pmapped_file->mapping); pmapped_file->mapping = NULL; pmapped_file->data = NULL; pmapped_file->size = 0; } YR_API void yr_filemap_unmap(YR_MAPPED_FILE* pmapped_file) { yr_filemap_unmap_fd(pmapped_file); if (pmapped_file->file != INVALID_HANDLE_VALUE) { CloseHandle(pmapped_file->file); pmapped_file->file = INVALID_HANDLE_VALUE; } } #else // POSIX YR_API void yr_filemap_unmap_fd(YR_MAPPED_FILE* pmapped_file) { if (pmapped_file->data != NULL) munmap((void*) pmapped_file->data, pmapped_file->size); pmapped_file->data = NULL; pmapped_file->size = 0; } YR_API void yr_filemap_unmap(YR_MAPPED_FILE* pmapped_file) { yr_filemap_unmap_fd(pmapped_file); if (pmapped_file->file != -1) { close(pmapped_file->file); pmapped_file->file = -1; } } #endif yara-4.5.3/libyara/grammar.c000066400000000000000000005636331501365277300157250ustar00rootroot00000000000000/* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. 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 . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output, and Bison version. */ #define YYBISON 30802 /* Bison version string. */ #define YYBISON_VERSION "3.8.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 1 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Substitute the variable and function names. */ #define yyparse yara_yyparse #define yylex yara_yylex #define yyerror yara_yyerror #define yydebug yara_yydebug #define yynerrs yara_yynerrs /* First part of user prologue. */ #line 32 "libyara/grammar.y" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(_MSC_VER) #define llabs _abs64 #endif #define YYERROR_VERBOSE #define YYMALLOC yr_malloc #define YYFREE yr_free #define FOR_EXPRESSION_ALL 1 #define FOR_EXPRESSION_ANY 2 #define FOR_EXPRESSION_NONE 3 #define FOR_ITERATION_ITERATOR 1 #define FOR_ITERATION_STRING_SET 2 // fail_with_error() is used in parser actions for aborting the parsing with // an error. If the error is recoverable (like syntax errors), the parser will // report the error and continue parsing the next rule. If the error is a // fatal, non-recoverable error, the parser will be completely aborted. #define fail_with_error(e) \ { \ compiler->last_error = e; \ yyerror(yyscanner, compiler, NULL); \ switch (e) \ { \ case ERROR_INSUFFICIENT_MEMORY: \ YYABORT; \ default: \ YYERROR; \ } \ } // fail_if_error() is used in parser actions for aborting the parsing if an // error has occurred. See fail_with_error for details. #define fail_if_error(e) \ if (e != ERROR_SUCCESS && e != ERROR_UNKNOWN_ESCAPE_SEQUENCE) \ { \ fail_with_error(e); \ } // check_type(expression, EXPRESSION_TYPE_INTEGER | EXPRESSION_TYPE_FLOAT) is // used to ensure that the type of "expression" is either integer or float, // the cleanup statements are executed if the condition is not met. #define check_type_with_cleanup(expression, expected_type, op, cleanup) \ if (((expression.type) & (expected_type)) == 0) \ { \ switch(expression.type) \ { \ case EXPRESSION_TYPE_INTEGER: \ yr_compiler_set_error_extra_info( \ compiler, "wrong type \"integer\" for " op " operator"); \ break; \ case EXPRESSION_TYPE_FLOAT: \ yr_compiler_set_error_extra_info( \ compiler, "wrong type \"float\" for " op " operator"); \ break; \ case EXPRESSION_TYPE_STRING: \ yr_compiler_set_error_extra_info( \ compiler, "wrong type \"string\" for " op " operator"); \ break; \ case EXPRESSION_TYPE_BOOLEAN: \ yr_compiler_set_error_extra_info( \ compiler, "wrong type \"boolean\" for " op " operator"); \ break; \ } \ cleanup; \ compiler->last_error = ERROR_WRONG_TYPE; \ yyerror(yyscanner, compiler, NULL); \ YYERROR; \ } // check_type(expression, EXPRESSION_TYPE_INTEGER | EXPRESSION_TYPE_FLOAT) is // used to ensure that the type of "expression" is either integer or float. #define check_type(expression, expected_type, op) \ check_type_with_cleanup(expression, expected_type, op, ) #define loop_vars_cleanup(loop_index) \ { \ YR_LOOP_CONTEXT* loop_ctx = &compiler->loop[loop_index]; \ for (int i = 0; i < loop_ctx->vars_count; i++) \ { \ yr_free((void*) loop_ctx->vars[i].identifier.ptr); \ loop_ctx->vars[i].identifier.ptr = NULL; \ loop_ctx->vars[i].identifier.ref = YR_ARENA_NULL_REF; \ } \ loop_ctx->vars_count = 0; \ } \ // Given a YR_EXPRESSION returns its identifier. It returns identifier.ptr if // not NULL and relies on identifier.ref if otherwise. #define expression_identifier(expr) \ ((expr).identifier.ptr != NULL ? \ (expr).identifier.ptr : \ (const char*) yr_arena_ref_to_ptr(compiler->arena, &(expr).identifier.ref)) #define DEFAULT_BASE64_ALPHABET \ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" #line 204 "libyara/grammar.c" # ifndef YY_CAST # ifdef __cplusplus # define YY_CAST(Type, Val) static_cast (Val) # define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) # else # define YY_CAST(Type, Val) ((Type) (Val)) # define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) # endif # endif # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # else # define YY_NULLPTR ((void*)0) # endif # endif /* Use api.header.include to #include this header instead of duplicating it here. */ #ifndef YY_YARA_YY_LIBYARA_GRAMMAR_H_INCLUDED # define YY_YARA_YY_LIBYARA_GRAMMAR_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yara_yydebug; #endif /* Token kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, _END_OF_FILE_ = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ _END_OF_INCLUDED_FILE_ = 258, /* "end of included file" */ _DOT_DOT_ = 259, /* ".." */ _RULE_ = 260, /* "" */ _PRIVATE_ = 261, /* "" */ _GLOBAL_ = 262, /* "" */ _META_ = 263, /* "" */ _STRINGS_ = 264, /* "" */ _CONDITION_ = 265, /* "" */ _IDENTIFIER_ = 266, /* "identifier" */ _STRING_IDENTIFIER_ = 267, /* "string identifier" */ _STRING_COUNT_ = 268, /* "string count" */ _STRING_OFFSET_ = 269, /* "string offset" */ _STRING_LENGTH_ = 270, /* "string length" */ _STRING_IDENTIFIER_WITH_WILDCARD_ = 271, /* "string identifier with wildcard" */ _NUMBER_ = 272, /* "integer number" */ _DOUBLE_ = 273, /* "floating point number" */ _INTEGER_FUNCTION_ = 274, /* "integer function" */ _TEXT_STRING_ = 275, /* "text string" */ _HEX_STRING_ = 276, /* "hex string" */ _REGEXP_ = 277, /* "regular expression" */ _ASCII_ = 278, /* "" */ _WIDE_ = 279, /* "" */ _XOR_ = 280, /* "" */ _BASE64_ = 281, /* "" */ _BASE64_WIDE_ = 282, /* "" */ _NOCASE_ = 283, /* "" */ _FULLWORD_ = 284, /* "" */ _AT_ = 285, /* "" */ _FILESIZE_ = 286, /* "" */ _ENTRYPOINT_ = 287, /* "" */ _ALL_ = 288, /* "" */ _ANY_ = 289, /* "" */ _NONE_ = 290, /* "" */ _IN_ = 291, /* "" */ _OF_ = 292, /* "" */ _FOR_ = 293, /* "" */ _THEM_ = 294, /* "" */ _MATCHES_ = 295, /* "" */ _CONTAINS_ = 296, /* "" */ _STARTSWITH_ = 297, /* "" */ _ENDSWITH_ = 298, /* "" */ _ICONTAINS_ = 299, /* "" */ _ISTARTSWITH_ = 300, /* "" */ _IENDSWITH_ = 301, /* "" */ _IEQUALS_ = 302, /* "" */ _IMPORT_ = 303, /* "" */ _TRUE_ = 304, /* "" */ _FALSE_ = 305, /* "" */ _OR_ = 306, /* "" */ _AND_ = 307, /* "" */ _NOT_ = 308, /* "" */ _DEFINED_ = 309, /* "" */ _EQ_ = 310, /* "==" */ _NEQ_ = 311, /* "!=" */ _LT_ = 312, /* "<" */ _LE_ = 313, /* "<=" */ _GT_ = 314, /* ">" */ _GE_ = 315, /* ">=" */ _SHIFT_LEFT_ = 316, /* "<<" */ _SHIFT_RIGHT_ = 317, /* ">>" */ UNARY_MINUS = 318 /* UNARY_MINUS */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Token kinds. */ #define YYEMPTY -2 #define _END_OF_FILE_ 0 #define YYerror 256 #define YYUNDEF 257 #define _END_OF_INCLUDED_FILE_ 258 #define _DOT_DOT_ 259 #define _RULE_ 260 #define _PRIVATE_ 261 #define _GLOBAL_ 262 #define _META_ 263 #define _STRINGS_ 264 #define _CONDITION_ 265 #define _IDENTIFIER_ 266 #define _STRING_IDENTIFIER_ 267 #define _STRING_COUNT_ 268 #define _STRING_OFFSET_ 269 #define _STRING_LENGTH_ 270 #define _STRING_IDENTIFIER_WITH_WILDCARD_ 271 #define _NUMBER_ 272 #define _DOUBLE_ 273 #define _INTEGER_FUNCTION_ 274 #define _TEXT_STRING_ 275 #define _HEX_STRING_ 276 #define _REGEXP_ 277 #define _ASCII_ 278 #define _WIDE_ 279 #define _XOR_ 280 #define _BASE64_ 281 #define _BASE64_WIDE_ 282 #define _NOCASE_ 283 #define _FULLWORD_ 284 #define _AT_ 285 #define _FILESIZE_ 286 #define _ENTRYPOINT_ 287 #define _ALL_ 288 #define _ANY_ 289 #define _NONE_ 290 #define _IN_ 291 #define _OF_ 292 #define _FOR_ 293 #define _THEM_ 294 #define _MATCHES_ 295 #define _CONTAINS_ 296 #define _STARTSWITH_ 297 #define _ENDSWITH_ 298 #define _ICONTAINS_ 299 #define _ISTARTSWITH_ 300 #define _IENDSWITH_ 301 #define _IEQUALS_ 302 #define _IMPORT_ 303 #define _TRUE_ 304 #define _FALSE_ 305 #define _OR_ 306 #define _AND_ 307 #define _NOT_ 308 #define _DEFINED_ 309 #define _EQ_ 310 #define _NEQ_ 311 #define _LT_ 312 #define _LE_ 313 #define _GT_ 314 #define _GE_ 315 #define _SHIFT_LEFT_ 316 #define _SHIFT_RIGHT_ 317 #define UNARY_MINUS 318 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 343 "libyara/grammar.y" YR_EXPRESSION expression; SIZED_STRING* sized_string; char* c_string; int64_t integer; double double_; YR_MODIFIER modifier; YR_ENUMERATION enumeration; YR_ARENA_REF tag; YR_ARENA_REF rule; YR_ARENA_REF meta; YR_ARENA_REF string; #line 398 "libyara/grammar.c" }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif int yara_yyparse (void *yyscanner, YR_COMPILER* compiler); #endif /* !YY_YARA_YY_LIBYARA_GRAMMAR_H_INCLUDED */ /* Symbol kind. */ enum yysymbol_kind_t { YYSYMBOL_YYEMPTY = -2, YYSYMBOL_YYEOF = 0, /* "end of file" */ YYSYMBOL_YYerror = 1, /* error */ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ YYSYMBOL__END_OF_INCLUDED_FILE_ = 3, /* "end of included file" */ YYSYMBOL__DOT_DOT_ = 4, /* ".." */ YYSYMBOL__RULE_ = 5, /* "" */ YYSYMBOL__PRIVATE_ = 6, /* "" */ YYSYMBOL__GLOBAL_ = 7, /* "" */ YYSYMBOL__META_ = 8, /* "" */ YYSYMBOL__STRINGS_ = 9, /* "" */ YYSYMBOL__CONDITION_ = 10, /* "" */ YYSYMBOL__IDENTIFIER_ = 11, /* "identifier" */ YYSYMBOL__STRING_IDENTIFIER_ = 12, /* "string identifier" */ YYSYMBOL__STRING_COUNT_ = 13, /* "string count" */ YYSYMBOL__STRING_OFFSET_ = 14, /* "string offset" */ YYSYMBOL__STRING_LENGTH_ = 15, /* "string length" */ YYSYMBOL__STRING_IDENTIFIER_WITH_WILDCARD_ = 16, /* "string identifier with wildcard" */ YYSYMBOL__NUMBER_ = 17, /* "integer number" */ YYSYMBOL__DOUBLE_ = 18, /* "floating point number" */ YYSYMBOL__INTEGER_FUNCTION_ = 19, /* "integer function" */ YYSYMBOL__TEXT_STRING_ = 20, /* "text string" */ YYSYMBOL__HEX_STRING_ = 21, /* "hex string" */ YYSYMBOL__REGEXP_ = 22, /* "regular expression" */ YYSYMBOL__ASCII_ = 23, /* "" */ YYSYMBOL__WIDE_ = 24, /* "" */ YYSYMBOL__XOR_ = 25, /* "" */ YYSYMBOL__BASE64_ = 26, /* "" */ YYSYMBOL__BASE64_WIDE_ = 27, /* "" */ YYSYMBOL__NOCASE_ = 28, /* "" */ YYSYMBOL__FULLWORD_ = 29, /* "" */ YYSYMBOL__AT_ = 30, /* "" */ YYSYMBOL__FILESIZE_ = 31, /* "" */ YYSYMBOL__ENTRYPOINT_ = 32, /* "" */ YYSYMBOL__ALL_ = 33, /* "" */ YYSYMBOL__ANY_ = 34, /* "" */ YYSYMBOL__NONE_ = 35, /* "" */ YYSYMBOL__IN_ = 36, /* "" */ YYSYMBOL__OF_ = 37, /* "" */ YYSYMBOL__FOR_ = 38, /* "" */ YYSYMBOL__THEM_ = 39, /* "" */ YYSYMBOL__MATCHES_ = 40, /* "" */ YYSYMBOL__CONTAINS_ = 41, /* "" */ YYSYMBOL__STARTSWITH_ = 42, /* "" */ YYSYMBOL__ENDSWITH_ = 43, /* "" */ YYSYMBOL__ICONTAINS_ = 44, /* "" */ YYSYMBOL__ISTARTSWITH_ = 45, /* "" */ YYSYMBOL__IENDSWITH_ = 46, /* "" */ YYSYMBOL__IEQUALS_ = 47, /* "" */ YYSYMBOL__IMPORT_ = 48, /* "" */ YYSYMBOL__TRUE_ = 49, /* "" */ YYSYMBOL__FALSE_ = 50, /* "" */ YYSYMBOL__OR_ = 51, /* "" */ YYSYMBOL__AND_ = 52, /* "" */ YYSYMBOL__NOT_ = 53, /* "" */ YYSYMBOL__DEFINED_ = 54, /* "" */ YYSYMBOL__EQ_ = 55, /* "==" */ YYSYMBOL__NEQ_ = 56, /* "!=" */ YYSYMBOL__LT_ = 57, /* "<" */ YYSYMBOL__LE_ = 58, /* "<=" */ YYSYMBOL__GT_ = 59, /* ">" */ YYSYMBOL__GE_ = 60, /* ">=" */ YYSYMBOL__SHIFT_LEFT_ = 61, /* "<<" */ YYSYMBOL__SHIFT_RIGHT_ = 62, /* ">>" */ YYSYMBOL_63_ = 63, /* '|' */ YYSYMBOL_64_ = 64, /* '^' */ YYSYMBOL_65_ = 65, /* '&' */ YYSYMBOL_66_ = 66, /* '+' */ YYSYMBOL_67_ = 67, /* '-' */ YYSYMBOL_68_ = 68, /* '*' */ YYSYMBOL_69_ = 69, /* '\\' */ YYSYMBOL_70_ = 70, /* '%' */ YYSYMBOL_71_ = 71, /* '~' */ YYSYMBOL_UNARY_MINUS = 72, /* UNARY_MINUS */ YYSYMBOL_73_include_ = 73, /* "include" */ YYSYMBOL_74_ = 74, /* '{' */ YYSYMBOL_75_ = 75, /* '}' */ YYSYMBOL_76_ = 76, /* ':' */ YYSYMBOL_77_ = 77, /* '=' */ YYSYMBOL_78_ = 78, /* '(' */ YYSYMBOL_79_ = 79, /* ')' */ YYSYMBOL_80_ = 80, /* '.' */ YYSYMBOL_81_ = 81, /* '[' */ YYSYMBOL_82_ = 82, /* ']' */ YYSYMBOL_83_ = 83, /* ',' */ YYSYMBOL_YYACCEPT = 84, /* $accept */ YYSYMBOL_rules = 85, /* rules */ YYSYMBOL_import = 86, /* import */ YYSYMBOL_rule = 87, /* rule */ YYSYMBOL_88_1 = 88, /* @1 */ YYSYMBOL_89_2 = 89, /* $@2 */ YYSYMBOL_meta = 90, /* meta */ YYSYMBOL_strings = 91, /* strings */ YYSYMBOL_condition = 92, /* condition */ YYSYMBOL_rule_modifiers = 93, /* rule_modifiers */ YYSYMBOL_rule_modifier = 94, /* rule_modifier */ YYSYMBOL_tags = 95, /* tags */ YYSYMBOL_tag_list = 96, /* tag_list */ YYSYMBOL_meta_declarations = 97, /* meta_declarations */ YYSYMBOL_meta_declaration = 98, /* meta_declaration */ YYSYMBOL_string_declarations = 99, /* string_declarations */ YYSYMBOL_string_declaration = 100, /* string_declaration */ YYSYMBOL_101_3 = 101, /* $@3 */ YYSYMBOL_102_4 = 102, /* $@4 */ YYSYMBOL_103_5 = 103, /* $@5 */ YYSYMBOL_string_modifiers = 104, /* string_modifiers */ YYSYMBOL_string_modifier = 105, /* string_modifier */ YYSYMBOL_regexp_modifiers = 106, /* regexp_modifiers */ YYSYMBOL_regexp_modifier = 107, /* regexp_modifier */ YYSYMBOL_hex_modifiers = 108, /* hex_modifiers */ YYSYMBOL_hex_modifier = 109, /* hex_modifier */ YYSYMBOL_identifier = 110, /* identifier */ YYSYMBOL_arguments = 111, /* arguments */ YYSYMBOL_arguments_list = 112, /* arguments_list */ YYSYMBOL_regexp = 113, /* regexp */ YYSYMBOL_boolean_expression = 114, /* boolean_expression */ YYSYMBOL_expression = 115, /* expression */ YYSYMBOL_116_6 = 116, /* $@6 */ YYSYMBOL_117_7 = 117, /* $@7 */ YYSYMBOL_118_8 = 118, /* $@8 */ YYSYMBOL_119_9 = 119, /* $@9 */ YYSYMBOL_for_iteration = 120, /* for_iteration */ YYSYMBOL_for_variables = 121, /* for_variables */ YYSYMBOL_iterator = 122, /* iterator */ YYSYMBOL_set = 123, /* set */ YYSYMBOL_range = 124, /* range */ YYSYMBOL_enumeration = 125, /* enumeration */ YYSYMBOL_string_iterator = 126, /* string_iterator */ YYSYMBOL_string_set = 127, /* string_set */ YYSYMBOL_128_10 = 128, /* $@10 */ YYSYMBOL_string_enumeration = 129, /* string_enumeration */ YYSYMBOL_string_enumeration_item = 130, /* string_enumeration_item */ YYSYMBOL_rule_set = 131, /* rule_set */ YYSYMBOL_132_11 = 132, /* $@11 */ YYSYMBOL_rule_enumeration = 133, /* rule_enumeration */ YYSYMBOL_rule_enumeration_item = 134, /* rule_enumeration_item */ YYSYMBOL_for_expression = 135, /* for_expression */ YYSYMBOL_for_quantifier = 136, /* for_quantifier */ YYSYMBOL_primary_expression = 137 /* primary_expression */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; #ifdef short # undef short #endif /* On compilers that do not define __PTRDIFF_MAX__ etc., make sure and (if available) are included so that the code can choose integer types of a good width. */ #ifndef __PTRDIFF_MAX__ # include /* INFRINGES ON USER NAME SPACE */ # if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YY_STDINT_H # endif #endif /* Narrow types that promote to a signed type and that can represent a signed or unsigned integer of at least N bits. In tables they can save space and decrease cache pressure. Promoting to a signed type helps avoid bugs in integer arithmetic. */ #ifdef __INT_LEAST8_MAX__ typedef __INT_LEAST8_TYPE__ yytype_int8; #elif defined YY_STDINT_H typedef int_least8_t yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef __INT_LEAST16_MAX__ typedef __INT_LEAST16_TYPE__ yytype_int16; #elif defined YY_STDINT_H typedef int_least16_t yytype_int16; #else typedef short yytype_int16; #endif /* Work around bug in HP-UX 11.23, which defines these macros incorrectly for preprocessor constants. This workaround can likely be removed in 2023, as HPE has promised support for HP-UX 11.23 (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of . */ #ifdef __hpux # undef UINT_LEAST8_MAX # undef UINT_LEAST16_MAX # define UINT_LEAST8_MAX 255 # define UINT_LEAST16_MAX 65535 #endif #if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ typedef __UINT_LEAST8_TYPE__ yytype_uint8; #elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ && UINT_LEAST8_MAX <= INT_MAX) typedef uint_least8_t yytype_uint8; #elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX typedef unsigned char yytype_uint8; #else typedef short yytype_uint8; #endif #if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ typedef __UINT_LEAST16_TYPE__ yytype_uint16; #elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ && UINT_LEAST16_MAX <= INT_MAX) typedef uint_least16_t yytype_uint16; #elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX typedef unsigned short yytype_uint16; #else typedef int yytype_uint16; #endif #ifndef YYPTRDIFF_T # if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ # define YYPTRDIFF_T __PTRDIFF_TYPE__ # define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ # elif defined PTRDIFF_MAX # ifndef ptrdiff_t # include /* INFRINGES ON USER NAME SPACE */ # endif # define YYPTRDIFF_T ptrdiff_t # define YYPTRDIFF_MAXIMUM PTRDIFF_MAX # else # define YYPTRDIFF_T long # define YYPTRDIFF_MAXIMUM LONG_MAX # endif #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned # endif #endif #define YYSIZE_MAXIMUM \ YY_CAST (YYPTRDIFF_T, \ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ ? YYPTRDIFF_MAXIMUM \ : YY_CAST (YYSIZE_T, -1))) #define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) /* Stored state numbers (used for stacks). */ typedef yytype_int16 yy_state_t; /* State numbers in computations. */ typedef int yy_state_fast_t; #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE_PURE # if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) # else # define YY_ATTRIBUTE_PURE # endif #endif #ifndef YY_ATTRIBUTE_UNUSED # if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) # else # define YY_ATTRIBUTE_UNUSED # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YY_USE(E) ((void) (E)) #else # define YY_USE(E) /* empty */ #endif /* Suppress an incorrect diagnostic about yylval being uninitialized. */ #if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ # if __GNUC__ * 100 + __GNUC_MINOR__ < 407 # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") # else # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # endif # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ # define YY_IGNORE_USELESS_CAST_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") # define YY_IGNORE_USELESS_CAST_END \ _Pragma ("GCC diagnostic pop") #endif #ifndef YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_END #endif #define YY_ASSERT(E) ((void) (0 && (E))) #if 1 /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* 1 */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yy_state_t yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYPTRDIFF_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / YYSIZEOF (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYPTRDIFF_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 480 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 84 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 54 /* YYNRULES -- Number of rules. */ #define YYNRULES 169 /* YYNSTATES -- Number of states. */ #define YYNSTATES 276 /* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK 319 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM as returned by yylex, with out-of-bounds checking. */ #define YYTRANSLATE(YYX) \ (0 <= (YYX) && (YYX) <= YYMAXUTOK \ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ : YYSYMBOL_YYUNDEF) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex. */ static const yytype_int8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 70, 65, 2, 78, 79, 68, 66, 83, 67, 80, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 76, 2, 2, 77, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 81, 69, 82, 64, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 74, 63, 75, 71, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 72, 73 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { 0, 362, 362, 363, 364, 365, 366, 367, 368, 372, 380, 393, 398, 392, 429, 432, 448, 451, 466, 474, 475, 480, 481, 487, 490, 506, 515, 557, 558, 563, 580, 594, 608, 622, 640, 641, 647, 646, 663, 662, 683, 682, 707, 713, 773, 774, 775, 776, 777, 778, 784, 805, 836, 841, 858, 863, 883, 884, 898, 899, 900, 901, 902, 906, 907, 921, 925, 1021, 1069, 1130, 1175, 1176, 1180, 1215, 1268, 1323, 1354, 1361, 1368, 1381, 1392, 1403, 1414, 1425, 1436, 1447, 1458, 1473, 1489, 1501, 1576, 1614, 1518, 1743, 1766, 1778, 1806, 1825, 1848, 1896, 1903, 1910, 1909, 1956, 1955, 2006, 2014, 2022, 2030, 2038, 2046, 2054, 2058, 2066, 2067, 2092, 2112, 2140, 2214, 2246, 2264, 2275, 2318, 2334, 2354, 2364, 2363, 2372, 2386, 2387, 2392, 2402, 2417, 2416, 2429, 2430, 2435, 2468, 2493, 2549, 2556, 2562, 2568, 2578, 2582, 2590, 2602, 2616, 2623, 2630, 2655, 2667, 2679, 2691, 2706, 2718, 2733, 2776, 2797, 2832, 2867, 2901, 2926, 2943, 2953, 2963, 2973, 2983, 3003, 3023 }; #endif /** Accessing symbol of state STATE. */ #define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) #if 1 /* The user-facing name of the symbol whose (internal) number is YYSYMBOL. No bounds checking. */ static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "\"end of file\"", "error", "\"invalid token\"", "\"end of included file\"", "\"..\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"identifier\"", "\"string identifier\"", "\"string count\"", "\"string offset\"", "\"string length\"", "\"string identifier with wildcard\"", "\"integer number\"", "\"floating point number\"", "\"integer function\"", "\"text string\"", "\"hex string\"", "\"regular expression\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"\"", "\"==\"", "\"!=\"", "\"<\"", "\"<=\"", "\">\"", "\">=\"", "\"<<\"", "\">>\"", "'|'", "'^'", "'&'", "'+'", "'-'", "'*'", "'\\\\'", "'%'", "'~'", "UNARY_MINUS", "\"include\"", "'{'", "'}'", "':'", "'='", "'('", "')'", "'.'", "'['", "']'", "','", "$accept", "rules", "import", "rule", "@1", "$@2", "meta", "strings", "condition", "rule_modifiers", "rule_modifier", "tags", "tag_list", "meta_declarations", "meta_declaration", "string_declarations", "string_declaration", "$@3", "$@4", "$@5", "string_modifiers", "string_modifier", "regexp_modifiers", "regexp_modifier", "hex_modifiers", "hex_modifier", "identifier", "arguments", "arguments_list", "regexp", "boolean_expression", "expression", "$@6", "$@7", "$@8", "$@9", "for_iteration", "for_variables", "iterator", "set", "range", "enumeration", "string_iterator", "string_set", "$@10", "string_enumeration", "string_enumeration_item", "rule_set", "$@11", "rule_enumeration", "rule_enumeration_item", "for_expression", "for_quantifier", "primary_expression", YY_NULLPTR }; static const char * yysymbol_name (yysymbol_kind_t yysymbol) { return yytname[yysymbol]; } #endif #define YYPACT_NINF (-170) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) #define YYTABLE_NINF (-139) #define yytable_value_is_error(Yyn) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int16 yypact[] = { -170, 32, -170, 28, -170, 0, -170, -170, 137, -170, -170, -170, -170, -170, 11, -170, -170, -170, -170, -40, 59, 1, -170, 83, 91, -170, 39, 99, 106, 53, -170, 46, 106, -170, 122, 127, 54, -170, 71, 122, -170, 74, 77, -170, -170, -170, -170, 148, 118, -170, 78, -170, -170, 134, 158, 165, -170, 42, 131, 110, 119, -170, -170, 121, -170, -170, -170, -170, -170, -170, -170, 144, -170, -170, 78, 78, 212, 212, 78, 55, -170, 95, -170, 166, -170, 291, -170, -170, -170, 212, 130, 130, 212, 212, 212, 212, 7, 390, -170, -170, -170, -170, 95, 125, 251, 78, 194, 212, -170, -170, -35, 187, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 170, 145, 96, 204, 390, 212, -170, -170, 199, 301, 333, 352, -170, 68, 212, -170, -170, 149, 141, 146, -170, 311, 78, 78, -170, 222, 47, -170, -170, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 18, 18, 400, 151, 410, 126, 126, -170, -170, -35, -170, -170, -170, -170, 157, 160, 161, -170, -170, -170, -170, -170, -170, -170, -170, -170, -170, -170, 189, -170, -170, -170, -170, -33, 164, -2, -170, 78, -170, 184, -170, -3, 231, 212, 130, -170, -170, 228, 226, 227, 212, -170, -170, -170, -170, -9, 238, 146, -170, -170, -62, -170, 202, 35, -170, 390, -170, -60, 192, 193, 371, 195, 212, 55, -170, -170, -170, -170, -170, -3, -170, -170, 231, 257, -170, -170, -170, -170, 78, 43, 189, -170, -170, 196, -37, -170, 212, -170, -170, 390 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { 2, 0, 1, 19, 8, 0, 4, 3, 0, 9, 7, 6, 5, 10, 0, 21, 22, 20, 11, 23, 0, 0, 25, 24, 14, 26, 0, 16, 0, 0, 12, 0, 15, 27, 0, 0, 0, 28, 0, 17, 34, 0, 0, 30, 29, 32, 33, 0, 36, 35, 0, 13, 31, 0, 0, 0, 66, 86, 151, 153, 155, 147, 148, 0, 149, 74, 144, 145, 140, 141, 142, 0, 76, 77, 0, 0, 0, 0, 0, 156, 169, 18, 75, 0, 139, 111, 42, 56, 63, 0, 0, 0, 0, 0, 0, 0, 0, 138, 99, 100, 157, 166, 0, 75, 111, 70, 0, 0, 103, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 39, 41, 87, 0, 88, 150, 0, 0, 0, 0, 89, 0, 0, 112, 143, 0, 71, 72, 67, 0, 0, 0, 127, 125, 93, 94, 78, 79, 81, 83, 80, 82, 84, 85, 109, 110, 105, 107, 106, 108, 167, 168, 165, 163, 164, 158, 159, 160, 161, 0, 162, 48, 45, 44, 49, 52, 54, 46, 47, 43, 62, 59, 58, 60, 61, 57, 65, 64, 0, 152, 154, 146, 115, 0, 0, 0, 69, 0, 68, 104, 102, 0, 0, 0, 0, 95, 96, 0, 0, 0, 0, 125, 114, 124, 91, 0, 0, 73, 130, 131, 0, 128, 136, 0, 134, 98, 97, 0, 0, 0, 0, 0, 0, 117, 113, 118, 120, 116, 126, 0, 137, 133, 0, 0, 50, 53, 55, 121, 0, 0, 122, 129, 135, 0, 0, 119, 0, 51, 92, 123 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { -170, -170, 273, 274, -170, -170, -170, -170, -170, -170, -170, -170, -170, -170, 246, -170, 241, -170, -170, -170, -170, -170, -170, -170, -170, -170, 51, -170, -170, 173, -50, -75, -170, -170, -170, -170, -170, -170, -170, -170, -90, -170, -170, -169, -170, -170, 30, 101, -170, -170, 29, 218, -170, -66 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { 0, 1, 6, 7, 19, 35, 27, 30, 42, 8, 17, 21, 23, 32, 33, 39, 40, 53, 54, 55, 135, 195, 136, 201, 137, 203, 79, 151, 152, 80, 102, 82, 147, 247, 157, 156, 210, 211, 250, 251, 140, 265, 228, 160, 217, 236, 237, 161, 218, 239, 240, 83, 84, 85 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { 81, 141, 56, 103, 158, 97, 158, 259, 146, 234, 100, 101, 104, 235, 108, 109, 221, 254, -90, 260, 13, 255, 18, 138, 98, 99, 142, 143, 144, 145, 153, 9, 2, 3, 231, 4, 20, -19, -19, -19, 229, 155, 274, 159, -90, 227, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 186, 248, 22, 43, 89, 204, 44, 24, 5, 219, 90, 208, 5, 232, 186, 220, 130, 131, 132, 133, 148, 56, 57, 58, 59, 60, 25, 61, 62, 63, 64, 26, 65, 10, 196, 45, 46, 209, 215, 216, 29, 66, 67, 68, 69, 70, 257, 28, 71, 31, 258, 197, 198, 47, 271, 36, 199, 200, 272, 72, 73, 34, 242, 74, 75, 105, 38, 106, 107, 41, 233, -40, -38, 252, 14, 15, 16, 76, 108, 109, 48, 77, 50, 187, 51, 241, 86, 56, 78, 58, 59, 60, 246, 61, 62, 63, 64, 52, 65, 91, 188, 189, 190, 191, 192, 193, 194, 66, 67, 68, 69, 70, 87, 56, 266, 58, 59, 60, 88, 61, 62, 63, 64, 92, 65, 226, 132, 133, 148, -75, -75, 94, 93, 66, 67, 110, 149, 154, 275, 185, 139, 65, 202, 76, 125, 126, 270, 77, 129, 130, 131, 132, 133, 148, 95, 56, 213, 58, 59, 60, 212, 61, 62, 63, 64, -132, 65, 223, 109, 76, 224, 225, 230, 77, 238, 66, 67, 243, 244, 245, 95, 253, 125, 126, 127, 128, 129, 130, 131, 132, 133, 148, 125, 126, 127, 128, 129, 130, 131, 132, 133, 148, 256, 261, 262, 264, 269, 273, 11, 12, 37, 76, 49, 205, 249, 77, 162, 267, 222, 268, -138, 96, 95, 111, 112, 113, 114, 115, 116, 117, 118, 0, 0, 0, 0, 0, 0, 0, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 0, 0, 0, 0, 0, 0, -138, 0, 150, 111, 112, 113, 114, 115, 116, 117, 118, 0, 0, 0, 0, 0, 0, 0, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 125, 126, 127, 128, 129, 130, 131, 132, 133, 148, 125, 126, 127, 128, 129, 130, 131, 132, 133, 148, 0, 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 214, 125, 126, 127, 128, 129, 130, 131, 132, 133, 148, 0, 0, 0, 0, 0, 0, 0, 0, 207, 125, 126, 127, 128, 129, 130, 131, 132, 133, 148, 0, 0, 0, 0, 0, 0, 0, 0, 150, 125, 126, 127, 128, 129, 130, 131, 132, 133, 148, 0, 0, 0, 0, 0, 0, 0, 0, 263, 125, 126, 127, 128, 129, 130, 131, 132, 133, 148, 125, 126, 0, 128, 129, 130, 131, 132, 133, 148, 125, 126, 0, 0, 0, 130, 131, 132, 133, 148 }; static const yytype_int16 yycheck[] = { 50, 91, 11, 78, 39, 71, 39, 67, 1, 12, 76, 77, 78, 16, 51, 52, 185, 79, 11, 79, 20, 83, 11, 89, 74, 75, 92, 93, 94, 95, 105, 3, 0, 1, 36, 3, 76, 5, 6, 7, 209, 107, 79, 78, 37, 78, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 78, 11, 17, 30, 139, 20, 74, 48, 30, 36, 11, 48, 83, 148, 36, 66, 67, 68, 69, 70, 11, 12, 13, 14, 15, 11, 17, 18, 19, 20, 8, 22, 73, 6, 49, 50, 37, 156, 157, 9, 31, 32, 33, 34, 35, 79, 76, 38, 11, 83, 23, 24, 67, 79, 77, 28, 29, 83, 49, 50, 76, 220, 53, 54, 78, 12, 80, 81, 10, 213, 21, 22, 231, 5, 6, 7, 67, 51, 52, 77, 71, 76, 6, 75, 219, 20, 11, 78, 13, 14, 15, 226, 17, 18, 19, 20, 17, 22, 36, 23, 24, 25, 26, 27, 28, 29, 31, 32, 33, 34, 35, 22, 11, 248, 13, 14, 15, 21, 17, 18, 19, 20, 81, 22, 4, 68, 69, 70, 51, 52, 78, 81, 31, 32, 37, 79, 11, 272, 37, 78, 22, 6, 67, 61, 62, 264, 71, 65, 66, 67, 68, 69, 70, 78, 11, 83, 13, 14, 15, 79, 17, 18, 19, 20, 11, 22, 78, 52, 67, 78, 78, 76, 71, 11, 31, 32, 17, 20, 20, 78, 11, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 68, 79, 79, 78, 17, 79, 3, 3, 32, 67, 39, 82, 231, 71, 111, 255, 185, 258, 37, 71, 78, 40, 41, 42, 43, 44, 45, 46, 47, -1, -1, -1, -1, -1, -1, -1, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, -1, -1, -1, -1, -1, 37, -1, 79, 40, 41, 42, 43, 44, 45, 46, 47, -1, -1, -1, -1, -1, -1, -1, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, 82, -1, -1, -1, -1, -1, -1, -1, -1, -1, 82, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, -1, -1, -1, -1, -1, -1, -1, 79, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, -1, -1, -1, -1, -1, -1, -1, 79, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, -1, -1, -1, -1, -1, -1, -1, -1, 79, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 61, 62, -1, 64, 65, 66, 67, 68, 69, 70, 61, 62, -1, -1, -1, 66, 67, 68, 69, 70 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 85, 0, 1, 3, 48, 86, 87, 93, 3, 73, 86, 87, 20, 5, 6, 7, 94, 11, 88, 76, 95, 11, 96, 74, 11, 8, 90, 76, 9, 91, 11, 97, 98, 76, 89, 77, 98, 12, 99, 100, 10, 92, 17, 20, 49, 50, 67, 77, 100, 76, 75, 17, 101, 102, 103, 11, 12, 13, 14, 15, 17, 18, 19, 20, 22, 31, 32, 33, 34, 35, 38, 49, 50, 53, 54, 67, 71, 78, 110, 113, 114, 115, 135, 136, 137, 20, 22, 21, 30, 36, 36, 81, 81, 78, 78, 135, 137, 114, 114, 137, 137, 114, 115, 137, 78, 80, 81, 51, 52, 37, 40, 41, 42, 43, 44, 45, 46, 47, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 104, 106, 108, 137, 78, 124, 124, 137, 137, 137, 137, 1, 116, 70, 79, 79, 111, 112, 115, 11, 137, 119, 118, 39, 78, 127, 131, 113, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 37, 137, 6, 23, 24, 25, 26, 27, 28, 29, 105, 6, 23, 24, 28, 29, 107, 6, 109, 137, 82, 82, 79, 11, 37, 120, 121, 79, 83, 82, 114, 114, 128, 132, 30, 36, 127, 131, 78, 78, 78, 4, 78, 126, 127, 76, 36, 83, 115, 12, 16, 129, 130, 11, 133, 134, 137, 124, 17, 20, 20, 137, 117, 78, 110, 122, 123, 124, 11, 79, 83, 68, 79, 83, 67, 79, 79, 79, 79, 78, 125, 137, 130, 134, 17, 114, 79, 83, 79, 79, 137 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_uint8 yyr1[] = { 0, 84, 85, 85, 85, 85, 85, 85, 85, 85, 86, 88, 89, 87, 90, 90, 91, 91, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 98, 98, 98, 98, 99, 99, 101, 100, 102, 100, 103, 100, 104, 104, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 106, 106, 107, 107, 107, 107, 107, 108, 108, 109, 110, 110, 110, 110, 111, 111, 112, 112, 113, 114, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 116, 117, 115, 115, 115, 115, 115, 115, 115, 115, 115, 118, 115, 119, 115, 115, 115, 115, 115, 115, 115, 115, 115, 120, 120, 121, 121, 122, 122, 123, 123, 124, 125, 125, 126, 128, 127, 127, 129, 129, 130, 130, 132, 131, 133, 133, 134, 134, 135, 135, 136, 136, 136, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 0, 2, 2, 3, 3, 3, 2, 3, 2, 0, 0, 11, 0, 3, 0, 3, 3, 0, 2, 1, 1, 0, 2, 1, 2, 1, 2, 3, 3, 4, 3, 3, 1, 2, 0, 5, 0, 5, 0, 5, 0, 2, 1, 1, 1, 1, 1, 1, 4, 6, 1, 4, 1, 4, 0, 2, 1, 1, 1, 1, 1, 0, 2, 1, 1, 3, 4, 4, 0, 1, 1, 3, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 0, 0, 9, 3, 3, 4, 4, 5, 5, 2, 2, 0, 4, 0, 4, 3, 3, 3, 3, 3, 3, 1, 3, 3, 2, 1, 3, 1, 1, 3, 1, 5, 1, 3, 1, 0, 4, 1, 1, 3, 1, 1, 0, 4, 1, 3, 1, 2, 1, 1, 1, 1, 1, 3, 1, 1, 4, 1, 1, 1, 3, 1, 4, 1, 4, 1, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 1 }; enum { YYENOMEM = -2 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYNOMEM goto yyexhaustedlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (yyscanner, compiler, YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Backward compatibility with an undocumented macro. Use YYerror or YYUNDEF. */ #define YYERRCODE YYUNDEF /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Kind, Value, yyscanner, compiler); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*-----------------------------------. | Print this symbol's value on YYO. | `-----------------------------------*/ static void yy_symbol_value_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, void *yyscanner, YR_COMPILER* compiler) { FILE *yyoutput = yyo; YY_USE (yyoutput); YY_USE (yyscanner); YY_USE (compiler); if (!yyvaluep) return; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /*---------------------------. | Print this symbol on YYO. | `---------------------------*/ static void yy_symbol_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, void *yyscanner, YR_COMPILER* compiler) { YYFPRINTF (yyo, "%s %s (", yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); yy_symbol_value_print (yyo, yykind, yyvaluep, yyscanner, compiler); YYFPRINTF (yyo, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, int yyrule, void *yyscanner, YR_COMPILER* compiler) { int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), &yyvsp[(yyi + 1) - (yynrhs)], yyscanner, compiler); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, Rule, yyscanner, compiler); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) ((void) 0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif /* Context of a parse error. */ typedef struct { yy_state_t *yyssp; yysymbol_kind_t yytoken; } yypcontext_t; /* Put in YYARG at most YYARGN of the expected tokens given the current YYCTX, and return the number of tokens stored in YYARG. If YYARG is null, return the number of expected tokens (guaranteed to be less than YYNTOKENS). Return YYENOMEM on memory exhaustion. Return 0 if there are more than YYARGN expected tokens, yet fill YYARG up to YYARGN. */ static int yypcontext_expected_tokens (const yypcontext_t *yyctx, yysymbol_kind_t yyarg[], int yyargn) { /* Actual size of YYARG. */ int yycount = 0; int yyn = yypact[+*yyctx->yyssp]; if (!yypact_value_is_default (yyn)) { /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. In other words, skip the first -YYN actions for this state because they are default actions. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yyx; for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYSYMBOL_YYerror && !yytable_value_is_error (yytable[yyx + yyn])) { if (!yyarg) ++yycount; else if (yycount == yyargn) return 0; else yyarg[yycount++] = YY_CAST (yysymbol_kind_t, yyx); } } if (yyarg && yycount == 0 && 0 < yyargn) yyarg[0] = YYSYMBOL_YYEMPTY; return yycount; } #ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen(S) (YY_CAST (YYPTRDIFF_T, strlen (S))) # else /* Return the length of YYSTR. */ static YYPTRDIFF_T yystrlen (const char *yystr) { YYPTRDIFF_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif #endif #ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ static char * yystpcpy (char *yydest, const char *yysrc) { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif #endif #ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYPTRDIFF_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYPTRDIFF_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; else goto append; append: default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (yyres) return yystpcpy (yyres, yystr) - yyres; else return yystrlen (yystr); } #endif static int yy_syntax_error_arguments (const yypcontext_t *yyctx, yysymbol_kind_t yyarg[], int yyargn) { /* Actual size of YYARG. */ int yycount = 0; /* There are many possibilities here to consider: - If this state is a consistent state with a default action, then the only way this function was invoked is if the default action is an error action. In that case, don't check for expected tokens because there are none. - The only way there can be no lookahead present (in yychar) is if this state is a consistent state with a default action. Thus, detecting the absence of a lookahead is sufficient to determine that there is no unexpected or expected token to report. In that case, just report a simple "syntax error". - Don't assume there isn't a lookahead just because this state is a consistent state with a default action. There might have been a previous inconsistent state, consistent state with a non-default action, or user semantic action that manipulated yychar. - Of course, the expected token list depends on states to have correct lookahead information, and it depends on the parser not to perform extra reductions after fetching a lookahead from the scanner and before detecting a syntax error. Thus, state merging (from LALR or IELR) and default reductions corrupt the expected token list. However, the list is correct for canonical LR with one exception: it will still contain any token that will not be accepted due to an error action in a later state. */ if (yyctx->yytoken != YYSYMBOL_YYEMPTY) { int yyn; if (yyarg) yyarg[yycount] = yyctx->yytoken; ++yycount; yyn = yypcontext_expected_tokens (yyctx, yyarg ? yyarg + 1 : yyarg, yyargn - 1); if (yyn == YYENOMEM) return YYENOMEM; else yycount += yyn; } return yycount; } /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message about the unexpected token YYTOKEN for the state stack whose top is YYSSP. Return 0 if *YYMSG was successfully written. Return -1 if *YYMSG is not large enough to hold the message. In that case, also set *YYMSG_ALLOC to the required number of bytes. Return YYENOMEM if the required number of bytes is too large to store. */ static int yysyntax_error (YYPTRDIFF_T *yymsg_alloc, char **yymsg, const yypcontext_t *yyctx) { enum { YYARGS_MAX = 5 }; /* Internationalized format string. */ const char *yyformat = YY_NULLPTR; /* Arguments of yyformat: reported tokens (one for the "unexpected", one per "expected"). */ yysymbol_kind_t yyarg[YYARGS_MAX]; /* Cumulated lengths of YYARG. */ YYPTRDIFF_T yysize = 0; /* Actual size of YYARG. */ int yycount = yy_syntax_error_arguments (yyctx, yyarg, YYARGS_MAX); if (yycount == YYENOMEM) return YYENOMEM; switch (yycount) { #define YYCASE_(N, S) \ case N: \ yyformat = S; \ break default: /* Avoid compiler warnings. */ YYCASE_(0, YY_("syntax error")); YYCASE_(1, YY_("syntax error, unexpected %s")); YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); #undef YYCASE_ } /* Compute error message size. Don't count the "%s"s, but reserve room for the terminator. */ yysize = yystrlen (yyformat) - 2 * yycount + 1; { int yyi; for (yyi = 0; yyi < yycount; ++yyi) { YYPTRDIFF_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyarg[yyi]]); if (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM) yysize = yysize1; else return YYENOMEM; } } if (*yymsg_alloc < yysize) { *yymsg_alloc = 2 * yysize; if (! (yysize <= *yymsg_alloc && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; return -1; } /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ { char *yyp = *yymsg; int yyi = 0; while ((*yyp = *yyformat) != '\0') if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yytname[yyarg[yyi++]]); yyformat += 2; } else { ++yyp; ++yyformat; } } return 0; } /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, yysymbol_kind_t yykind, YYSTYPE *yyvaluep, void *yyscanner, YR_COMPILER* compiler) { YY_USE (yyvaluep); YY_USE (yyscanner); YY_USE (compiler); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN switch (yykind) { case YYSYMBOL__IDENTIFIER_: /* "identifier" */ #line 313 "libyara/grammar.y" { yr_free(((*yyvaluep).c_string)); ((*yyvaluep).c_string) = NULL; } #line 1780 "libyara/grammar.c" break; case YYSYMBOL__STRING_IDENTIFIER_: /* "string identifier" */ #line 317 "libyara/grammar.y" { yr_free(((*yyvaluep).c_string)); ((*yyvaluep).c_string) = NULL; } #line 1786 "libyara/grammar.c" break; case YYSYMBOL__STRING_COUNT_: /* "string count" */ #line 314 "libyara/grammar.y" { yr_free(((*yyvaluep).c_string)); ((*yyvaluep).c_string) = NULL; } #line 1792 "libyara/grammar.c" break; case YYSYMBOL__STRING_OFFSET_: /* "string offset" */ #line 315 "libyara/grammar.y" { yr_free(((*yyvaluep).c_string)); ((*yyvaluep).c_string) = NULL; } #line 1798 "libyara/grammar.c" break; case YYSYMBOL__STRING_LENGTH_: /* "string length" */ #line 316 "libyara/grammar.y" { yr_free(((*yyvaluep).c_string)); ((*yyvaluep).c_string) = NULL; } #line 1804 "libyara/grammar.c" break; case YYSYMBOL__STRING_IDENTIFIER_WITH_WILDCARD_: /* "string identifier with wildcard" */ #line 318 "libyara/grammar.y" { yr_free(((*yyvaluep).c_string)); ((*yyvaluep).c_string) = NULL; } #line 1810 "libyara/grammar.c" break; case YYSYMBOL__TEXT_STRING_: /* "text string" */ #line 319 "libyara/grammar.y" { yr_free(((*yyvaluep).sized_string)); ((*yyvaluep).sized_string) = NULL; } #line 1816 "libyara/grammar.c" break; case YYSYMBOL__HEX_STRING_: /* "hex string" */ #line 320 "libyara/grammar.y" { yr_free(((*yyvaluep).sized_string)); ((*yyvaluep).sized_string) = NULL; } #line 1822 "libyara/grammar.c" break; case YYSYMBOL__REGEXP_: /* "regular expression" */ #line 321 "libyara/grammar.y" { yr_free(((*yyvaluep).sized_string)); ((*yyvaluep).sized_string) = NULL; } #line 1828 "libyara/grammar.c" break; case YYSYMBOL_string_modifiers: /* string_modifiers */ #line 334 "libyara/grammar.y" { if (((*yyvaluep).modifier).alphabet != NULL) { yr_free(((*yyvaluep).modifier).alphabet); ((*yyvaluep).modifier).alphabet = NULL; } } #line 1840 "libyara/grammar.c" break; case YYSYMBOL_string_modifier: /* string_modifier */ #line 326 "libyara/grammar.y" { if (((*yyvaluep).modifier).alphabet != NULL) { yr_free(((*yyvaluep).modifier).alphabet); ((*yyvaluep).modifier).alphabet = NULL; } } #line 1852 "libyara/grammar.c" break; case YYSYMBOL_arguments: /* arguments */ #line 323 "libyara/grammar.y" { yr_free(((*yyvaluep).c_string)); ((*yyvaluep).c_string) = NULL; } #line 1858 "libyara/grammar.c" break; case YYSYMBOL_arguments_list: /* arguments_list */ #line 324 "libyara/grammar.y" { yr_free(((*yyvaluep).c_string)); ((*yyvaluep).c_string) = NULL; } #line 1864 "libyara/grammar.c" break; default: break; } YY_IGNORE_MAYBE_UNINITIALIZED_END } /*----------. | yyparse. | `----------*/ int yyparse (void *yyscanner, YR_COMPILER* compiler) { /* Lookahead token kind. */ int yychar; /* The semantic value of the lookahead symbol. */ /* Default value used for initialization, for pacifying older GCCs or non-GCC compilers. */ YY_INITIAL_VALUE (static YYSTYPE yyval_default;) YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); /* Number of syntax errors so far. */ int yynerrs = 0; yy_state_fast_t yystate = 0; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus = 0; /* Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* Their size. */ YYPTRDIFF_T yystacksize = YYINITDEPTH; /* The state stack: array, bottom, top. */ yy_state_t yyssa[YYINITDEPTH]; yy_state_t *yyss = yyssa; yy_state_t *yyssp = yyss; /* The semantic value stack: array, bottom, top. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; YYSTYPE *yyvsp = yyvs; int yyn; /* The return value of yyparse. */ int yyresult; /* Lookahead symbol kind. */ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYPTRDIFF_T yymsg_alloc = sizeof yymsgbuf; #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; YYDPRINTF ((stderr, "Starting parse\n")); yychar = YYEMPTY; /* Cause a token to be read. */ goto yysetstate; /*------------------------------------------------------------. | yynewstate -- push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; /*--------------------------------------------------------------------. | yysetstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: YYDPRINTF ((stderr, "Entering state %d\n", yystate)); YY_ASSERT (0 <= yystate && yystate < YYNSTATES); YY_IGNORE_USELESS_CAST_BEGIN *yyssp = YY_CAST (yy_state_t, yystate); YY_IGNORE_USELESS_CAST_END YY_STACK_PRINT (yyss, yyssp); if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE YYNOMEM; #else { /* Get the current used size of the three stacks, in elements. */ YYPTRDIFF_T yysize = yyssp - yyss + 1; # if defined yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ yy_state_t *yyss1 = yyss; YYSTYPE *yyvs1 = yyvs; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * YYSIZEOF (*yyssp), &yyvs1, yysize * YYSIZEOF (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } # else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) YYNOMEM; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yy_state_t *yyss1 = yyss; union yyalloc *yyptr = YY_CAST (union yyalloc *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) YYNOMEM; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YY_IGNORE_USELESS_CAST_BEGIN YYDPRINTF ((stderr, "Stack size increased to %ld\n", YY_CAST (long, yystacksize))); YY_IGNORE_USELESS_CAST_END if (yyss + yystacksize - 1 <= yyssp) YYABORT; } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token\n")); yychar = yylex (&yylval, yyscanner, compiler); } if (yychar <= _END_OF_FILE_) { yychar = _END_OF_FILE_; yytoken = YYSYMBOL_YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else if (yychar == YYerror) { /* The scanner already issued an error message, process directly to error recovery. But do not keep the error token as lookahead, it is too special and may lead us to an endless loop in error recovery. */ yychar = YYUNDEF; yytoken = YYSYMBOL_YYerror; goto yyerrlab1; } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Discard the shifted token. */ yychar = YYEMPTY; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 8: /* rules: rules "end of included file" */ #line 369 "libyara/grammar.y" { _yr_compiler_pop_file_name(compiler); } #line 2145 "libyara/grammar.c" break; case 9: /* rules: rules error "end of included file" */ #line 373 "libyara/grammar.y" { _yr_compiler_pop_file_name(compiler); } #line 2153 "libyara/grammar.c" break; case 10: /* import: "" "text string" */ #line 381 "libyara/grammar.y" { int result = yr_parser_reduce_import(yyscanner, (yyvsp[0].sized_string)); yr_free((yyvsp[0].sized_string)); fail_if_error(result); } #line 2165 "libyara/grammar.c" break; case 11: /* @1: %empty */ #line 393 "libyara/grammar.y" { fail_if_error(yr_parser_reduce_rule_declaration_phase_1( yyscanner, (int32_t) (yyvsp[-2].integer), (yyvsp[0].c_string), &(yyval.rule))); } #line 2174 "libyara/grammar.c" break; case 12: /* $@2: %empty */ #line 398 "libyara/grammar.y" { YR_RULE* rule = (YR_RULE*) yr_arena_ref_to_ptr( compiler->arena, &(yyvsp[-4].rule)); rule->tags = (char*) yr_arena_ref_to_ptr( compiler->arena, &(yyvsp[-3].tag)); rule->metas = (YR_META*) yr_arena_ref_to_ptr( compiler->arena, &(yyvsp[-1].meta)); rule->strings = (YR_STRING*) yr_arena_ref_to_ptr( compiler->arena, &(yyvsp[0].string)); } #line 2192 "libyara/grammar.c" break; case 13: /* rule: rule_modifiers "" "identifier" @1 tags '{' meta strings $@2 condition '}' */ #line 412 "libyara/grammar.y" { YR_RULE* rule = (YR_RULE*) yr_arena_ref_to_ptr( compiler->arena, &(yyvsp[-7].rule)); rule->required_strings = (yyvsp[-1].expression).required_strings.count; int result = yr_parser_reduce_rule_declaration_phase_2( yyscanner, &(yyvsp[-7].rule)); // rule created in phase 1 yr_free((yyvsp[-8].c_string)); fail_if_error(result); } #line 2209 "libyara/grammar.c" break; case 14: /* meta: %empty */ #line 429 "libyara/grammar.y" { (yyval.meta) = YR_ARENA_NULL_REF; } #line 2217 "libyara/grammar.c" break; case 15: /* meta: "" ':' meta_declarations */ #line 433 "libyara/grammar.y" { YR_META* meta = yr_arena_get_ptr( compiler->arena, YR_METAS_TABLE, (compiler->current_meta_idx - 1) * sizeof(YR_META)); meta->flags |= META_FLAGS_LAST_IN_RULE; (yyval.meta) = (yyvsp[0].meta); } #line 2232 "libyara/grammar.c" break; case 16: /* strings: %empty */ #line 448 "libyara/grammar.y" { (yyval.string) = YR_ARENA_NULL_REF; } #line 2240 "libyara/grammar.c" break; case 17: /* strings: "" ':' string_declarations */ #line 452 "libyara/grammar.y" { YR_STRING* string = (YR_STRING*) yr_arena_get_ptr( compiler->arena, YR_STRINGS_TABLE, (compiler->current_string_idx - 1) * sizeof(YR_STRING)); string->flags |= STRING_FLAGS_LAST_IN_RULE; (yyval.string) = (yyvsp[0].string); } #line 2255 "libyara/grammar.c" break; case 18: /* condition: "" ':' boolean_expression */ #line 467 "libyara/grammar.y" { (yyval.expression) = (yyvsp[0].expression); } #line 2263 "libyara/grammar.c" break; case 19: /* rule_modifiers: %empty */ #line 474 "libyara/grammar.y" { (yyval.integer) = 0; } #line 2269 "libyara/grammar.c" break; case 20: /* rule_modifiers: rule_modifiers rule_modifier */ #line 475 "libyara/grammar.y" { (yyval.integer) = (yyvsp[-1].integer) | (yyvsp[0].integer); } #line 2275 "libyara/grammar.c" break; case 21: /* rule_modifier: "" */ #line 480 "libyara/grammar.y" { (yyval.integer) = RULE_FLAGS_PRIVATE; } #line 2281 "libyara/grammar.c" break; case 22: /* rule_modifier: "" */ #line 481 "libyara/grammar.y" { (yyval.integer) = RULE_FLAGS_GLOBAL; } #line 2287 "libyara/grammar.c" break; case 23: /* tags: %empty */ #line 487 "libyara/grammar.y" { (yyval.tag) = YR_ARENA_NULL_REF; } #line 2295 "libyara/grammar.c" break; case 24: /* tags: ':' tag_list */ #line 491 "libyara/grammar.y" { // Tags list is represented in the arena as a sequence // of null-terminated strings, the sequence ends with an // additional null character. Here we write the ending null //character. Example: tag1\0tag2\0tag3\0\0 fail_if_error(yr_arena_write_string( yyget_extra(yyscanner)->arena, YR_SZ_POOL, "", NULL)); (yyval.tag) = (yyvsp[0].tag); } #line 2311 "libyara/grammar.c" break; case 25: /* tag_list: "identifier" */ #line 507 "libyara/grammar.y" { int result = yr_arena_write_string( yyget_extra(yyscanner)->arena, YR_SZ_POOL, (yyvsp[0].c_string), &(yyval.tag)); yr_free((yyvsp[0].c_string)); fail_if_error(result); } #line 2324 "libyara/grammar.c" break; case 26: /* tag_list: tag_list "identifier" */ #line 516 "libyara/grammar.y" { YR_ARENA_REF ref; // Write the new tag identifier. int result = yr_arena_write_string( yyget_extra(yyscanner)->arena, YR_SZ_POOL, (yyvsp[0].c_string), &ref); yr_free((yyvsp[0].c_string)); fail_if_error(result); // Get the address for the tag identifier just written. char* new_tag = (char*) yr_arena_ref_to_ptr( compiler->arena, &ref); // Take the address of first tag's identifier in the list. char* tag = (char*) yr_arena_ref_to_ptr( compiler->arena, &(yyval.tag)); // Search for duplicated tags. Tags are written one after // the other, with zeroes in between (i.e: tag1/0tag2/0tag3) // that's why can use tag < new_tag as the condition for the // loop. while (tag < new_tag) { if (strcmp(tag, new_tag) == 0) { yr_compiler_set_error_extra_info(compiler, tag); fail_with_error(ERROR_DUPLICATED_TAG_IDENTIFIER); } tag += strlen(tag) + 1; } (yyval.tag) = (yyvsp[-1].tag); } #line 2365 "libyara/grammar.c" break; case 27: /* meta_declarations: meta_declaration */ #line 557 "libyara/grammar.y" { (yyval.meta) = (yyvsp[0].meta); } #line 2371 "libyara/grammar.c" break; case 28: /* meta_declarations: meta_declarations meta_declaration */ #line 558 "libyara/grammar.y" { (yyval.meta) = (yyvsp[-1].meta); } #line 2377 "libyara/grammar.c" break; case 29: /* meta_declaration: "identifier" '=' "text string" */ #line 564 "libyara/grammar.y" { SIZED_STRING* sized_string = (yyvsp[0].sized_string); int result = yr_parser_reduce_meta_declaration( yyscanner, META_TYPE_STRING, (yyvsp[-2].c_string), sized_string->c_string, 0, &(yyval.meta)); yr_free((yyvsp[-2].c_string)); yr_free((yyvsp[0].sized_string)); fail_if_error(result); } #line 2398 "libyara/grammar.c" break; case 30: /* meta_declaration: "identifier" '=' "integer number" */ #line 581 "libyara/grammar.y" { int result = yr_parser_reduce_meta_declaration( yyscanner, META_TYPE_INTEGER, (yyvsp[-2].c_string), NULL, (yyvsp[0].integer), &(yyval.meta)); yr_free((yyvsp[-2].c_string)); fail_if_error(result); } #line 2416 "libyara/grammar.c" break; case 31: /* meta_declaration: "identifier" '=' '-' "integer number" */ #line 595 "libyara/grammar.y" { int result = yr_parser_reduce_meta_declaration( yyscanner, META_TYPE_INTEGER, (yyvsp[-3].c_string), NULL, -(yyvsp[0].integer), &(yyval.meta)); yr_free((yyvsp[-3].c_string)); fail_if_error(result); } #line 2434 "libyara/grammar.c" break; case 32: /* meta_declaration: "identifier" '=' "" */ #line 609 "libyara/grammar.y" { int result = yr_parser_reduce_meta_declaration( yyscanner, META_TYPE_BOOLEAN, (yyvsp[-2].c_string), NULL, true, &(yyval.meta)); yr_free((yyvsp[-2].c_string)); fail_if_error(result); } #line 2452 "libyara/grammar.c" break; case 33: /* meta_declaration: "identifier" '=' "" */ #line 623 "libyara/grammar.y" { int result = yr_parser_reduce_meta_declaration( yyscanner, META_TYPE_BOOLEAN, (yyvsp[-2].c_string), NULL, false, &(yyval.meta)); yr_free((yyvsp[-2].c_string)); fail_if_error(result); } #line 2470 "libyara/grammar.c" break; case 34: /* string_declarations: string_declaration */ #line 640 "libyara/grammar.y" { (yyval.string) = (yyvsp[0].string); } #line 2476 "libyara/grammar.c" break; case 35: /* string_declarations: string_declarations string_declaration */ #line 641 "libyara/grammar.y" { (yyval.string) = (yyvsp[-1].string); } #line 2482 "libyara/grammar.c" break; case 36: /* $@3: %empty */ #line 647 "libyara/grammar.y" { compiler->current_line = yyget_lineno(yyscanner); } #line 2490 "libyara/grammar.c" break; case 37: /* string_declaration: "string identifier" '=' $@3 "text string" string_modifiers */ #line 651 "libyara/grammar.y" { int result = yr_parser_reduce_string_declaration( yyscanner, (yyvsp[0].modifier), (yyvsp[-4].c_string), (yyvsp[-1].sized_string), &(yyval.string)); yr_free((yyvsp[-4].c_string)); yr_free((yyvsp[-1].sized_string)); yr_free((yyvsp[0].modifier).alphabet); fail_if_error(result); compiler->current_line = 0; } #line 2506 "libyara/grammar.c" break; case 38: /* $@4: %empty */ #line 663 "libyara/grammar.y" { compiler->current_line = yyget_lineno(yyscanner); } #line 2514 "libyara/grammar.c" break; case 39: /* string_declaration: "string identifier" '=' $@4 "regular expression" regexp_modifiers */ #line 667 "libyara/grammar.y" { int result; (yyvsp[0].modifier).flags |= STRING_FLAGS_REGEXP; result = yr_parser_reduce_string_declaration( yyscanner, (yyvsp[0].modifier), (yyvsp[-4].c_string), (yyvsp[-1].sized_string), &(yyval.string)); yr_free((yyvsp[-4].c_string)); yr_free((yyvsp[-1].sized_string)); fail_if_error(result); compiler->current_line = 0; } #line 2534 "libyara/grammar.c" break; case 40: /* $@5: %empty */ #line 683 "libyara/grammar.y" { compiler->current_line = yyget_lineno(yyscanner); } #line 2542 "libyara/grammar.c" break; case 41: /* string_declaration: "string identifier" '=' $@5 "hex string" hex_modifiers */ #line 687 "libyara/grammar.y" { int result; (yyvsp[0].modifier).flags |= STRING_FLAGS_HEXADECIMAL; result = yr_parser_reduce_string_declaration( yyscanner, (yyvsp[0].modifier), (yyvsp[-4].c_string), (yyvsp[-1].sized_string), &(yyval.string)); yr_free((yyvsp[-4].c_string)); yr_free((yyvsp[-1].sized_string)); fail_if_error(result); compiler->current_line = 0; } #line 2562 "libyara/grammar.c" break; case 42: /* string_modifiers: %empty */ #line 707 "libyara/grammar.y" { (yyval.modifier).flags = 0; (yyval.modifier).xor_min = 0; (yyval.modifier).xor_max = 0; (yyval.modifier).alphabet = NULL; } #line 2573 "libyara/grammar.c" break; case 43: /* string_modifiers: string_modifiers string_modifier */ #line 714 "libyara/grammar.y" { (yyval.modifier) = (yyvsp[-1].modifier); // Only set the xor minimum and maximum if we are dealing with the // xor modifier. If we don't check for this then we can end up with // "xor wide" resulting in whatever is on the stack for "wide" // overwriting the values for xor. if ((yyvsp[0].modifier).flags & STRING_FLAGS_XOR) { (yyval.modifier).xor_min = (yyvsp[0].modifier).xor_min; (yyval.modifier).xor_max = (yyvsp[0].modifier).xor_max; } // Only set the base64 alphabet if we are dealing with the base64 // modifier. If we don't check for this then we can end up with // "base64 ascii" resulting in whatever is on the stack for "ascii" // overwriting the values for base64. if (((yyvsp[0].modifier).flags & STRING_FLAGS_BASE64) || ((yyvsp[0].modifier).flags & STRING_FLAGS_BASE64_WIDE)) { if ((yyval.modifier).alphabet != NULL) { if (ss_compare((yyval.modifier).alphabet, (yyvsp[0].modifier).alphabet) != 0) { yr_compiler_set_error_extra_info( compiler, "can not specify multiple alphabets"); yr_free((yyvsp[0].modifier).alphabet); yr_free((yyval.modifier).alphabet); fail_with_error(ERROR_INVALID_MODIFIER); } else { yr_free((yyvsp[0].modifier).alphabet); } } else { (yyval.modifier).alphabet = (yyvsp[0].modifier).alphabet; } } if ((yyval.modifier).flags & (yyvsp[0].modifier).flags) { if ((yyval.modifier).alphabet != NULL) yr_free((yyval.modifier).alphabet); fail_with_error(ERROR_DUPLICATED_MODIFIER); } else { (yyval.modifier).flags = (yyval.modifier).flags | (yyvsp[0].modifier).flags; } } #line 2633 "libyara/grammar.c" break; case 44: /* string_modifier: "" */ #line 773 "libyara/grammar.y" { (yyval.modifier).flags = STRING_FLAGS_WIDE; } #line 2639 "libyara/grammar.c" break; case 45: /* string_modifier: "" */ #line 774 "libyara/grammar.y" { (yyval.modifier).flags = STRING_FLAGS_ASCII; } #line 2645 "libyara/grammar.c" break; case 46: /* string_modifier: "" */ #line 775 "libyara/grammar.y" { (yyval.modifier).flags = STRING_FLAGS_NO_CASE; } #line 2651 "libyara/grammar.c" break; case 47: /* string_modifier: "" */ #line 776 "libyara/grammar.y" { (yyval.modifier).flags = STRING_FLAGS_FULL_WORD; } #line 2657 "libyara/grammar.c" break; case 48: /* string_modifier: "" */ #line 777 "libyara/grammar.y" { (yyval.modifier).flags = STRING_FLAGS_PRIVATE; } #line 2663 "libyara/grammar.c" break; case 49: /* string_modifier: "" */ #line 779 "libyara/grammar.y" { (yyval.modifier).flags = STRING_FLAGS_XOR; (yyval.modifier).xor_min = 0; (yyval.modifier).xor_max = 255; } #line 2673 "libyara/grammar.c" break; case 50: /* string_modifier: "" '(' "integer number" ')' */ #line 785 "libyara/grammar.y" { int result = ERROR_SUCCESS; if ((yyvsp[-1].integer) < 0 || (yyvsp[-1].integer) > 255) { yr_compiler_set_error_extra_info(compiler, "invalid xor range"); result = ERROR_INVALID_MODIFIER; } fail_if_error(result); (yyval.modifier).flags = STRING_FLAGS_XOR; (yyval.modifier).xor_min = (uint8_t) (yyvsp[-1].integer); (yyval.modifier).xor_max = (uint8_t) (yyvsp[-1].integer); } #line 2693 "libyara/grammar.c" break; case 51: /* string_modifier: "" '(' "integer number" '-' "integer number" ')' */ #line 806 "libyara/grammar.y" { int result = ERROR_SUCCESS; if ((yyvsp[-3].integer) < 0) { yr_compiler_set_error_extra_info( compiler, "lower bound for xor range exceeded (min: 0)"); result = ERROR_INVALID_MODIFIER; } if ((yyvsp[-1].integer) > 255) { yr_compiler_set_error_extra_info( compiler, "upper bound for xor range exceeded (max: 255)"); result = ERROR_INVALID_MODIFIER; } if ((yyvsp[-3].integer) > (yyvsp[-1].integer)) { yr_compiler_set_error_extra_info( compiler, "xor lower bound exceeds upper bound"); result = ERROR_INVALID_MODIFIER; } fail_if_error(result); (yyval.modifier).flags = STRING_FLAGS_XOR; (yyval.modifier).xor_min = (uint8_t) (yyvsp[-3].integer); (yyval.modifier).xor_max = (uint8_t) (yyvsp[-1].integer); } #line 2728 "libyara/grammar.c" break; case 52: /* string_modifier: "" */ #line 837 "libyara/grammar.y" { (yyval.modifier).flags = STRING_FLAGS_BASE64; (yyval.modifier).alphabet = ss_new(DEFAULT_BASE64_ALPHABET); } #line 2737 "libyara/grammar.c" break; case 53: /* string_modifier: "" '(' "text string" ')' */ #line 842 "libyara/grammar.y" { int result = ERROR_SUCCESS; if ((yyvsp[-1].sized_string)->length != 64) { yr_free((yyvsp[-1].sized_string)); yr_compiler_set_error_extra_info( compiler, "length of base64 alphabet must be 64"); result = ERROR_INVALID_MODIFIER; } fail_if_error(result); (yyval.modifier).flags = STRING_FLAGS_BASE64; (yyval.modifier).alphabet = (yyvsp[-1].sized_string); } #line 2758 "libyara/grammar.c" break; case 54: /* string_modifier: "" */ #line 859 "libyara/grammar.y" { (yyval.modifier).flags = STRING_FLAGS_BASE64_WIDE; (yyval.modifier).alphabet = ss_new(DEFAULT_BASE64_ALPHABET); } #line 2767 "libyara/grammar.c" break; case 55: /* string_modifier: "" '(' "text string" ')' */ #line 864 "libyara/grammar.y" { int result = ERROR_SUCCESS; if ((yyvsp[-1].sized_string)->length != 64) { yr_free((yyvsp[-1].sized_string)); yr_compiler_set_error_extra_info( compiler, "length of base64 alphabet must be 64"); result = ERROR_INVALID_MODIFIER; } fail_if_error(result); (yyval.modifier).flags = STRING_FLAGS_BASE64_WIDE; (yyval.modifier).alphabet = (yyvsp[-1].sized_string); } #line 2788 "libyara/grammar.c" break; case 56: /* regexp_modifiers: %empty */ #line 883 "libyara/grammar.y" { (yyval.modifier).flags = 0; } #line 2794 "libyara/grammar.c" break; case 57: /* regexp_modifiers: regexp_modifiers regexp_modifier */ #line 885 "libyara/grammar.y" { if ((yyvsp[-1].modifier).flags & (yyvsp[0].modifier).flags) { fail_with_error(ERROR_DUPLICATED_MODIFIER); } else { (yyval.modifier).flags = (yyvsp[-1].modifier).flags | (yyvsp[0].modifier).flags; } } #line 2809 "libyara/grammar.c" break; case 58: /* regexp_modifier: "" */ #line 898 "libyara/grammar.y" { (yyval.modifier).flags = STRING_FLAGS_WIDE; } #line 2815 "libyara/grammar.c" break; case 59: /* regexp_modifier: "" */ #line 899 "libyara/grammar.y" { (yyval.modifier).flags = STRING_FLAGS_ASCII; } #line 2821 "libyara/grammar.c" break; case 60: /* regexp_modifier: "" */ #line 900 "libyara/grammar.y" { (yyval.modifier).flags = STRING_FLAGS_NO_CASE; } #line 2827 "libyara/grammar.c" break; case 61: /* regexp_modifier: "" */ #line 901 "libyara/grammar.y" { (yyval.modifier).flags = STRING_FLAGS_FULL_WORD; } #line 2833 "libyara/grammar.c" break; case 62: /* regexp_modifier: "" */ #line 902 "libyara/grammar.y" { (yyval.modifier).flags = STRING_FLAGS_PRIVATE; } #line 2839 "libyara/grammar.c" break; case 63: /* hex_modifiers: %empty */ #line 906 "libyara/grammar.y" { (yyval.modifier).flags = 0; } #line 2845 "libyara/grammar.c" break; case 64: /* hex_modifiers: hex_modifiers hex_modifier */ #line 908 "libyara/grammar.y" { if ((yyvsp[-1].modifier).flags & (yyvsp[0].modifier).flags) { fail_with_error(ERROR_DUPLICATED_MODIFIER); } else { (yyval.modifier).flags = (yyvsp[-1].modifier).flags | (yyvsp[0].modifier).flags; } } #line 2860 "libyara/grammar.c" break; case 65: /* hex_modifier: "" */ #line 921 "libyara/grammar.y" { (yyval.modifier).flags = STRING_FLAGS_PRIVATE; } #line 2866 "libyara/grammar.c" break; case 66: /* identifier: "identifier" */ #line 926 "libyara/grammar.y" { YR_EXPRESSION expr; int result = ERROR_SUCCESS; int var_index = yr_parser_lookup_loop_variable(yyscanner, (yyvsp[0].c_string), &expr); if (var_index >= 0) { // The identifier corresponds to a loop variable. result = yr_parser_emit_with_arg( yyscanner, OP_PUSH_M, var_index, NULL, NULL); // The expression associated to this identifier is the same one // associated to the loop variable. (yyval.expression) = expr; } else { // Search for identifier within the global namespace, where the // externals variables reside. YR_OBJECT* object = (YR_OBJECT*) yr_hash_table_lookup( compiler->objects_table, (yyvsp[0].c_string), NULL); YR_NAMESPACE* ns = (YR_NAMESPACE*) yr_arena_get_ptr( compiler->arena, YR_NAMESPACES_TABLE, compiler->current_namespace_idx * sizeof(struct YR_NAMESPACE)); if (object == NULL) { // If not found, search within the current namespace. object = (YR_OBJECT*) yr_hash_table_lookup( compiler->objects_table, (yyvsp[0].c_string), ns->name); } if (object != NULL) { YR_ARENA_REF ref; result = _yr_compiler_store_string( compiler, (yyvsp[0].c_string), &ref); if (result == ERROR_SUCCESS) result = yr_parser_emit_with_arg_reloc( yyscanner, OP_OBJ_LOAD, yr_arena_ref_to_ptr(compiler->arena, &ref), NULL, NULL); (yyval.expression).type = EXPRESSION_TYPE_OBJECT; (yyval.expression).value.object = object; (yyval.expression).identifier.ptr = NULL; (yyval.expression).identifier.ref = ref; } else { uint32_t rule_idx = yr_hash_table_lookup_uint32( compiler->rules_table, (yyvsp[0].c_string), ns->name); if (rule_idx != UINT32_MAX) { result = yr_parser_emit_with_arg( yyscanner, OP_PUSH_RULE, rule_idx, NULL, NULL); YR_RULE* rule = _yr_compiler_get_rule_by_idx(compiler, rule_idx); yr_arena_ptr_to_ref(compiler->arena, rule->identifier, &(yyval.expression).identifier.ref); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).value.integer = YR_UNDEFINED; (yyval.expression).identifier.ptr = NULL; (yyval.expression).required_strings.count = 0; } else { yr_compiler_set_error_extra_info(compiler, (yyvsp[0].c_string)); result = ERROR_UNDEFINED_IDENTIFIER; } } } yr_free((yyvsp[0].c_string)); fail_if_error(result); } #line 2966 "libyara/grammar.c" break; case 67: /* identifier: identifier '.' "identifier" */ #line 1022 "libyara/grammar.y" { int result = ERROR_SUCCESS; YR_OBJECT* field = NULL; if ((yyvsp[-2].expression).type == EXPRESSION_TYPE_OBJECT && (yyvsp[-2].expression).value.object->type == OBJECT_TYPE_STRUCTURE) { field = yr_object_lookup_field((yyvsp[-2].expression).value.object, (yyvsp[0].c_string)); if (field != NULL) { YR_ARENA_REF ref; result = _yr_compiler_store_string( compiler, (yyvsp[0].c_string), &ref); if (result == ERROR_SUCCESS) result = yr_parser_emit_with_arg_reloc( yyscanner, OP_OBJ_FIELD, yr_arena_ref_to_ptr(compiler->arena, &ref), NULL, NULL); (yyval.expression).type = EXPRESSION_TYPE_OBJECT; (yyval.expression).value.object = field; (yyval.expression).identifier.ref = ref; (yyval.expression).identifier.ptr = NULL; } else { yr_compiler_set_error_extra_info(compiler, (yyvsp[0].c_string)); result = ERROR_INVALID_FIELD_NAME; } } else { yr_compiler_set_error_extra_info( compiler, expression_identifier((yyvsp[-2].expression))); result = ERROR_NOT_A_STRUCTURE; } yr_free((yyvsp[0].c_string)); fail_if_error(result); } #line 3018 "libyara/grammar.c" break; case 68: /* identifier: identifier '[' primary_expression ']' */ #line 1070 "libyara/grammar.y" { int result = ERROR_SUCCESS; YR_OBJECT_ARRAY* array; YR_OBJECT_DICTIONARY* dict; if ((yyvsp[-3].expression).type == EXPRESSION_TYPE_OBJECT && (yyvsp[-3].expression).value.object->type == OBJECT_TYPE_ARRAY) { if ((yyvsp[-1].expression).type != EXPRESSION_TYPE_INTEGER) { yr_compiler_set_error_extra_info( compiler, "array indexes must be of integer type"); result = ERROR_WRONG_TYPE; } fail_if_error(result); result = yr_parser_emit( yyscanner, OP_INDEX_ARRAY, NULL); array = object_as_array((yyvsp[-3].expression).value.object); (yyval.expression).type = EXPRESSION_TYPE_OBJECT; (yyval.expression).value.object = array->prototype_item; (yyval.expression).identifier.ptr = array->identifier; (yyval.expression).identifier.ref = YR_ARENA_NULL_REF; } else if ((yyvsp[-3].expression).type == EXPRESSION_TYPE_OBJECT && (yyvsp[-3].expression).value.object->type == OBJECT_TYPE_DICTIONARY) { if ((yyvsp[-1].expression).type != EXPRESSION_TYPE_STRING) { yr_compiler_set_error_extra_info( compiler, "dictionary keys must be of string type"); result = ERROR_WRONG_TYPE; } fail_if_error(result); result = yr_parser_emit( yyscanner, OP_LOOKUP_DICT, NULL); dict = object_as_dictionary((yyvsp[-3].expression).value.object); (yyval.expression).type = EXPRESSION_TYPE_OBJECT; (yyval.expression).value.object = dict->prototype_item; (yyval.expression).identifier.ptr = dict->identifier; (yyval.expression).identifier.ref = YR_ARENA_NULL_REF; } else { yr_compiler_set_error_extra_info( compiler, expression_identifier((yyvsp[-3].expression))); result = ERROR_NOT_INDEXABLE; } fail_if_error(result); } #line 3082 "libyara/grammar.c" break; case 69: /* identifier: identifier '(' arguments ')' */ #line 1131 "libyara/grammar.y" { YR_ARENA_REF ref = YR_ARENA_NULL_REF; int result = ERROR_SUCCESS; if ((yyvsp[-3].expression).type == EXPRESSION_TYPE_OBJECT && (yyvsp[-3].expression).value.object->type == OBJECT_TYPE_FUNCTION) { YR_OBJECT_FUNCTION* function = object_as_function((yyvsp[-3].expression).value.object); result = yr_parser_check_types(compiler, function, (yyvsp[-1].c_string)); if (result == ERROR_SUCCESS) result = _yr_compiler_store_string( compiler, (yyvsp[-1].c_string), &ref); if (result == ERROR_SUCCESS) result = yr_parser_emit_with_arg_reloc( yyscanner, OP_CALL, yr_arena_ref_to_ptr(compiler->arena, &ref), NULL, NULL); (yyval.expression).type = EXPRESSION_TYPE_OBJECT; (yyval.expression).value.object = function->return_obj; (yyval.expression).identifier.ref = ref; (yyval.expression).identifier.ptr = NULL; } else { yr_compiler_set_error_extra_info( compiler, expression_identifier((yyvsp[-3].expression))); result = ERROR_NOT_A_FUNCTION; } yr_free((yyvsp[-1].c_string)); fail_if_error(result); } #line 3127 "libyara/grammar.c" break; case 70: /* arguments: %empty */ #line 1175 "libyara/grammar.y" { (yyval.c_string) = yr_strdup(""); } #line 3133 "libyara/grammar.c" break; case 71: /* arguments: arguments_list */ #line 1176 "libyara/grammar.y" { (yyval.c_string) = (yyvsp[0].c_string); } #line 3139 "libyara/grammar.c" break; case 72: /* arguments_list: expression */ #line 1181 "libyara/grammar.y" { (yyval.c_string) = (char*) yr_malloc(YR_MAX_FUNCTION_ARGS + 1); if ((yyval.c_string) == NULL) fail_with_error(ERROR_INSUFFICIENT_MEMORY); switch((yyvsp[0].expression).type) { case EXPRESSION_TYPE_INTEGER: strlcpy((yyval.c_string), "i", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_FLOAT: strlcpy((yyval.c_string), "f", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_BOOLEAN: strlcpy((yyval.c_string), "b", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_STRING: strlcpy((yyval.c_string), "s", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_REGEXP: strlcpy((yyval.c_string), "r", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_UNKNOWN: yr_free((yyval.c_string)); yr_compiler_set_error_extra_info( compiler, "unknown type for argument 1 in function call"); fail_with_error(ERROR_WRONG_TYPE); break; default: // An unknown expression type is OK iff an error ocurred. assert(compiler->last_error != ERROR_SUCCESS); } } #line 3178 "libyara/grammar.c" break; case 73: /* arguments_list: arguments_list ',' expression */ #line 1216 "libyara/grammar.y" { int result = ERROR_SUCCESS; if (strlen((yyvsp[-2].c_string)) == YR_MAX_FUNCTION_ARGS) { result = ERROR_TOO_MANY_ARGUMENTS; } else { switch((yyvsp[0].expression).type) { case EXPRESSION_TYPE_INTEGER: strlcat((yyvsp[-2].c_string), "i", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_FLOAT: strlcat((yyvsp[-2].c_string), "f", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_BOOLEAN: strlcat((yyvsp[-2].c_string), "b", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_STRING: strlcat((yyvsp[-2].c_string), "s", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_REGEXP: strlcat((yyvsp[-2].c_string), "r", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_UNKNOWN: result = ERROR_WRONG_TYPE; yr_compiler_set_error_extra_info_fmt( compiler, "unknown type for argument %zu in function call", // As we add one character per argument, the length of $1 is // the number of arguments parsed so far, and the argument // represented by is length of $1 plus one. strlen((yyvsp[-2].c_string)) + 1); break; default: // An unknown expression type is OK iff an error ocurred. assert(compiler->last_error != ERROR_SUCCESS); } } if (result != ERROR_SUCCESS) yr_free((yyvsp[-2].c_string)); fail_if_error(result); (yyval.c_string) = (yyvsp[-2].c_string); } #line 3231 "libyara/grammar.c" break; case 74: /* regexp: "regular expression" */ #line 1269 "libyara/grammar.y" { YR_ARENA_REF re_ref; RE_ERROR error; int result = ERROR_SUCCESS; int re_flags = 0; int parser_flags = RE_PARSER_FLAG_NONE; if ((yyvsp[0].sized_string)->flags & SIZED_STRING_FLAGS_NO_CASE) re_flags |= RE_FLAGS_NO_CASE; if ((yyvsp[0].sized_string)->flags & SIZED_STRING_FLAGS_DOT_ALL) re_flags |= RE_FLAGS_DOT_ALL; if (compiler->strict_escape) parser_flags |= RE_PARSER_FLAG_ENABLE_STRICT_ESCAPE_SEQUENCES; result = yr_re_compile( (yyvsp[0].sized_string)->c_string, re_flags, parser_flags, compiler->arena, &re_ref, &error); yr_free((yyvsp[0].sized_string)); if (result == ERROR_INVALID_REGULAR_EXPRESSION) yr_compiler_set_error_extra_info(compiler, error.message); if (result == ERROR_SUCCESS || result == ERROR_UNKNOWN_ESCAPE_SEQUENCE) { if (result == ERROR_UNKNOWN_ESCAPE_SEQUENCE) { yywarning( yyscanner, "unknown escape sequence"); } result = yr_parser_emit_with_arg_reloc( yyscanner, OP_PUSH, yr_arena_ref_to_ptr(compiler->arena, &re_ref), NULL, NULL); } fail_if_error(result); (yyval.expression).type = EXPRESSION_TYPE_REGEXP; } #line 3286 "libyara/grammar.c" break; case 75: /* boolean_expression: expression */ #line 1324 "libyara/grammar.y" { if ((yyvsp[0].expression).type == EXPRESSION_TYPE_STRING) { if (!YR_ARENA_IS_NULL_REF((yyvsp[0].expression).value.sized_string_ref)) { SIZED_STRING* sized_string = yr_arena_ref_to_ptr( compiler->arena, &(yyvsp[0].expression).value.sized_string_ref); yywarning(yyscanner, "using literal string \"%s\" in a boolean operation.", sized_string->c_string); } fail_if_error(yr_parser_emit( yyscanner, OP_STR_TO_BOOL, NULL)); } if ((yyvsp[0].expression).type != EXPRESSION_TYPE_BOOLEAN) { (yyval.expression).required_strings.count = 0; } else { (yyval.expression).required_strings.count = (yyvsp[0].expression).required_strings.count; } (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; } #line 3318 "libyara/grammar.c" break; case 76: /* expression: "" */ #line 1355 "libyara/grammar.y" { fail_if_error(yr_parser_emit_push_const(yyscanner, 1)); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 3329 "libyara/grammar.c" break; case 77: /* expression: "" */ #line 1362 "libyara/grammar.y" { fail_if_error(yr_parser_emit_push_const(yyscanner, 0)); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 3340 "libyara/grammar.c" break; case 78: /* expression: primary_expression "" regexp */ #line 1369 "libyara/grammar.y" { check_type((yyvsp[-2].expression), EXPRESSION_TYPE_STRING, "matches"); check_type((yyvsp[0].expression), EXPRESSION_TYPE_REGEXP, "matches"); fail_if_error(yr_parser_emit( yyscanner, OP_MATCHES, NULL)); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 3357 "libyara/grammar.c" break; case 79: /* expression: primary_expression "" primary_expression */ #line 1382 "libyara/grammar.y" { check_type((yyvsp[-2].expression), EXPRESSION_TYPE_STRING, "contains"); check_type((yyvsp[0].expression), EXPRESSION_TYPE_STRING, "contains"); fail_if_error(yr_parser_emit( yyscanner, OP_CONTAINS, NULL)); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 3372 "libyara/grammar.c" break; case 80: /* expression: primary_expression "" primary_expression */ #line 1393 "libyara/grammar.y" { check_type((yyvsp[-2].expression), EXPRESSION_TYPE_STRING, "icontains"); check_type((yyvsp[0].expression), EXPRESSION_TYPE_STRING, "icontains"); fail_if_error(yr_parser_emit( yyscanner, OP_ICONTAINS, NULL)); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 3387 "libyara/grammar.c" break; case 81: /* expression: primary_expression "" primary_expression */ #line 1404 "libyara/grammar.y" { check_type((yyvsp[-2].expression), EXPRESSION_TYPE_STRING, "startswith"); check_type((yyvsp[0].expression), EXPRESSION_TYPE_STRING, "startswith"); fail_if_error(yr_parser_emit( yyscanner, OP_STARTSWITH, NULL)); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 3402 "libyara/grammar.c" break; case 82: /* expression: primary_expression "" primary_expression */ #line 1415 "libyara/grammar.y" { check_type((yyvsp[-2].expression), EXPRESSION_TYPE_STRING, "istartswith"); check_type((yyvsp[0].expression), EXPRESSION_TYPE_STRING, "istartswith"); fail_if_error(yr_parser_emit( yyscanner, OP_ISTARTSWITH, NULL)); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 3417 "libyara/grammar.c" break; case 83: /* expression: primary_expression "" primary_expression */ #line 1426 "libyara/grammar.y" { check_type((yyvsp[-2].expression), EXPRESSION_TYPE_STRING, "endswith"); check_type((yyvsp[0].expression), EXPRESSION_TYPE_STRING, "endswith"); fail_if_error(yr_parser_emit( yyscanner, OP_ENDSWITH, NULL)); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 3432 "libyara/grammar.c" break; case 84: /* expression: primary_expression "" primary_expression */ #line 1437 "libyara/grammar.y" { check_type((yyvsp[-2].expression), EXPRESSION_TYPE_STRING, "iendswith"); check_type((yyvsp[0].expression), EXPRESSION_TYPE_STRING, "iendswith"); fail_if_error(yr_parser_emit( yyscanner, OP_IENDSWITH, NULL)); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 3447 "libyara/grammar.c" break; case 85: /* expression: primary_expression "" primary_expression */ #line 1448 "libyara/grammar.y" { check_type((yyvsp[-2].expression), EXPRESSION_TYPE_STRING, "iequals"); check_type((yyvsp[0].expression), EXPRESSION_TYPE_STRING, "iequals"); fail_if_error(yr_parser_emit( yyscanner, OP_IEQUALS, NULL)); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 3462 "libyara/grammar.c" break; case 86: /* expression: "string identifier" */ #line 1459 "libyara/grammar.y" { int result = yr_parser_reduce_string_identifier( yyscanner, (yyvsp[0].c_string), OP_FOUND, YR_UNDEFINED); yr_free((yyvsp[0].c_string)); fail_if_error(result); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 1; } #line 3481 "libyara/grammar.c" break; case 87: /* expression: "string identifier" "" primary_expression */ #line 1474 "libyara/grammar.y" { int result; check_type_with_cleanup((yyvsp[0].expression), EXPRESSION_TYPE_INTEGER, "at", yr_free((yyvsp[-2].c_string))); result = yr_parser_reduce_string_identifier( yyscanner, (yyvsp[-2].c_string), OP_FOUND_AT, (yyvsp[0].expression).value.integer); yr_free((yyvsp[-2].c_string)); fail_if_error(result); (yyval.expression).required_strings.count = 1; (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; } #line 3501 "libyara/grammar.c" break; case 88: /* expression: "string identifier" "" range */ #line 1490 "libyara/grammar.y" { int result = yr_parser_reduce_string_identifier( yyscanner, (yyvsp[-2].c_string), OP_FOUND_IN, YR_UNDEFINED); yr_free((yyvsp[-2].c_string)); fail_if_error(result); (yyval.expression).required_strings.count = 1; (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; } #line 3517 "libyara/grammar.c" break; case 89: /* expression: "" for_expression error */ #line 1502 "libyara/grammar.y" { // Free all the loop variable identifiers, including the variables for // the current loop (represented by loop_index), and set loop_index to // -1. This is OK even if we have nested loops. If an error occurs while // parsing the inner loop, it will be propagated to the outer loop // anyways, so it's safe to do this cleanup while processing the error // for the inner loop. for (int i = 0; i <= compiler->loop_index; i++) { loop_vars_cleanup(i); } compiler->loop_index = -1; YYERROR; } #line 3538 "libyara/grammar.c" break; case 90: /* $@6: %empty */ #line 1576 "libyara/grammar.y" { // var_frame is used for accessing local variables used in this loop. // All local variables are accessed using var_frame as a reference, // like var_frame + 0, var_frame + 1, etc. Here we initialize var_frame // with the correct value, which depends on the number of variables // defined by any outer loops. int var_frame; int result = ERROR_SUCCESS; if (compiler->loop_index + 1 == YR_MAX_LOOP_NESTING) result = ERROR_LOOP_NESTING_LIMIT_EXCEEDED; fail_if_error(result); compiler->loop_index++; // This loop uses internal variables besides the ones explicitly // defined by the user. compiler->loop[compiler->loop_index].vars_internal_count = \ YR_INTERNAL_LOOP_VARS; // Initialize the number of variables, this number will be incremented // as variable declaration are processed by for_variables. compiler->loop[compiler->loop_index].vars_count = 0; var_frame = _yr_compiler_get_var_frame(compiler); fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_CLEAR_M, var_frame + 0, NULL, NULL)); fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_CLEAR_M, var_frame + 1, NULL, NULL)); fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_POP_M, var_frame + 2, NULL, NULL)); } #line 3580 "libyara/grammar.c" break; case 91: /* $@7: %empty */ #line 1614 "libyara/grammar.y" { YR_LOOP_CONTEXT* loop_ctx = &compiler->loop[compiler->loop_index]; YR_FIXUP* fixup; YR_ARENA_REF loop_start_ref; YR_ARENA_REF jmp_offset_ref; int var_frame = _yr_compiler_get_var_frame(compiler); fail_if_error(yr_parser_emit( yyscanner, OP_ITER_NEXT, &loop_start_ref)); // For each variable generate an instruction that pops the value from // the stack and store it into one memory slot starting at var_frame + // YR_INTERNAL_LOOP_VARS because the first YR_INTERNAL_LOOP_VARS slots // in the frame are for the internal variables. for (int i = 0; i < loop_ctx->vars_count; i++) { fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_POP_M, var_frame + YR_INTERNAL_LOOP_VARS + i, NULL, NULL)); } fail_if_error(yr_parser_emit_with_arg_int32( yyscanner, OP_JTRUE_P, 0, // still don't know the jump offset, use 0 for now. NULL, &jmp_offset_ref)); // We still don't know the jump's target, so we push a fixup entry // in the stack, so that the jump's offset can be set once we know it. fixup = (YR_FIXUP*) yr_malloc(sizeof(YR_FIXUP)); if (fixup == NULL) fail_with_error(ERROR_INSUFFICIENT_MEMORY); fixup->ref = jmp_offset_ref; fixup->next = compiler->fixup_stack_head; compiler->fixup_stack_head = fixup; loop_ctx->start_ref = loop_start_ref; } #line 3633 "libyara/grammar.c" break; case 92: /* expression: "" for_expression $@6 for_iteration ':' $@7 '(' boolean_expression ')' */ #line 1663 "libyara/grammar.y" { int32_t jmp_offset; YR_FIXUP* fixup; YR_ARENA_REF pop_ref; int var_frame = _yr_compiler_get_var_frame(compiler); if ((yyvsp[-5].integer) == FOR_ITERATION_STRING_SET) { compiler->loop_for_of_var_index = -1; } fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_INCR_M, var_frame + 1, NULL, NULL)); fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_PUSH_M, var_frame + 0, NULL, NULL)); fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_PUSH_M, var_frame + 2, NULL, NULL)); fail_if_error(yr_parser_emit(yyscanner, OP_ITER_CONDITION, NULL)); fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_ADD_M, var_frame + 0, NULL, NULL)); jmp_offset = \ compiler->loop[compiler->loop_index].start_ref.offset - yr_arena_get_current_offset(compiler->arena, YR_CODE_SECTION); fail_if_error(yr_parser_emit_with_arg_int32( yyscanner, OP_JTRUE_P, jmp_offset, NULL, NULL)); fail_if_error(yr_parser_emit( yyscanner, OP_POP, &pop_ref)); // Pop from the stack the fixup entry containing the reference to // the jump offset that needs to be fixed. fixup = compiler->fixup_stack_head; compiler->fixup_stack_head = fixup->next; // The fixup entry has a reference to the jump offset that need // to be fixed, convert the address into a pointer. int32_t* jmp_offset_addr = (int32_t*) yr_arena_ref_to_ptr( compiler->arena, &fixup->ref); // The reference in the fixup entry points to the jump's offset // but the jump instruction is one byte before, that's why we add // one to the offset. jmp_offset = pop_ref.offset - fixup->ref.offset + 1; // Fix the jump's offset. memcpy(jmp_offset_addr, &jmp_offset, sizeof(jmp_offset)); yr_free(fixup); fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_PUSH_M, var_frame + 1, NULL, NULL)); fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_PUSH_M, var_frame + 0, NULL, NULL)); fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_PUSH_M, var_frame + 2, NULL, NULL)); fail_if_error(yr_parser_emit( yyscanner, OP_ITER_END, NULL)); loop_vars_cleanup(compiler->loop_index); compiler->loop_index--; (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 3718 "libyara/grammar.c" break; case 93: /* expression: for_expression "" string_set */ #line 1744 "libyara/grammar.y" { if ((yyvsp[-2].expression).type == EXPRESSION_TYPE_INTEGER && (yyvsp[-2].expression).value.integer > (yyvsp[0].integer)) { yywarning(yyscanner, "expression always false - requesting %" PRId64 " of %" PRId64 ".", (yyvsp[-2].expression).value.integer, (yyvsp[0].integer)); } if (((yyvsp[-2].expression).type == EXPRESSION_TYPE_INTEGER && (yyvsp[-2].expression).value.integer > 0) || ((yyvsp[-2].expression).type == EXPRESSION_TYPE_QUANTIFIER && ((yyvsp[-2].expression).value.integer == FOR_EXPRESSION_ALL || (yyvsp[-2].expression).value.integer == FOR_EXPRESSION_ANY))) { (yyval.expression).required_strings.count = 1; } else { (yyval.expression).required_strings.count = 0; } yr_parser_emit_with_arg(yyscanner, OP_OF, OF_STRING_SET, NULL, NULL); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; } #line 3745 "libyara/grammar.c" break; case 94: /* expression: for_expression "" rule_set */ #line 1767 "libyara/grammar.y" { if ((yyvsp[-2].expression).type == EXPRESSION_TYPE_INTEGER && (yyvsp[-2].expression).value.integer > (yyvsp[0].integer)) { yywarning(yyscanner, "expression always false - requesting %" PRId64 " of %" PRId64 ".", (yyvsp[-2].expression).value.integer, (yyvsp[0].integer)); } yr_parser_emit_with_arg(yyscanner, OP_OF, OF_RULE_SET, NULL, NULL); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 3761 "libyara/grammar.c" break; case 95: /* expression: primary_expression '%' "" string_set */ #line 1779 "libyara/grammar.y" { check_type((yyvsp[-3].expression), EXPRESSION_TYPE_INTEGER, "%"); // The value of primary_expression can be undefined because // it could be a variable for which don't know the value during // compiling time. However, if the value is defined it should be // in the range [1,100]. if (!IS_UNDEFINED((yyvsp[-3].expression).value.integer) && ((yyvsp[-3].expression).value.integer < 1 || (yyvsp[-3].expression).value.integer > 100)) { yr_compiler_set_error_extra_info( compiler, "percentage must be between 1 and 100 (inclusive)"); fail_with_error(ERROR_INVALID_PERCENTAGE); } if (!IS_UNDEFINED((yyvsp[-3].expression).value.integer)) { (yyval.expression).required_strings.count = 1; } else { (yyval.expression).required_strings.count = 0; } yr_parser_emit_with_arg(yyscanner, OP_OF_PERCENT, OF_STRING_SET, NULL, NULL); } #line 3793 "libyara/grammar.c" break; case 96: /* expression: primary_expression '%' "" rule_set */ #line 1807 "libyara/grammar.y" { check_type((yyvsp[-3].expression), EXPRESSION_TYPE_INTEGER, "%"); // The value of primary_expression can be undefined because // it could be a variable for which don't know the value during // compiling time. However, if the value is defined it should be // in the range [1,100]. if (!IS_UNDEFINED((yyvsp[-3].expression).value.integer) && ((yyvsp[-3].expression).value.integer < 1 || (yyvsp[-3].expression).value.integer > 100)) { yr_compiler_set_error_extra_info( compiler, "percentage must be between 1 and 100 (inclusive)"); fail_with_error(ERROR_INVALID_PERCENTAGE); } yr_parser_emit_with_arg(yyscanner, OP_OF_PERCENT, OF_RULE_SET, NULL, NULL); } #line 3816 "libyara/grammar.c" break; case 97: /* expression: for_expression "" string_set "" range */ #line 1826 "libyara/grammar.y" { if ((yyvsp[-4].expression).type == EXPRESSION_TYPE_INTEGER && (yyvsp[-4].expression).value.integer > (yyvsp[-2].integer)) { yywarning(yyscanner, "expression always false - requesting %" PRId64 " of %" PRId64 ".", (yyvsp[-4].expression).value.integer, (yyvsp[-2].integer)); } if (((yyvsp[-4].expression).type == EXPRESSION_TYPE_INTEGER && (yyvsp[-4].expression).value.integer > 0) || ((yyvsp[-4].expression).type == EXPRESSION_TYPE_QUANTIFIER && ((yyvsp[-4].expression).value.integer == FOR_EXPRESSION_ALL || (yyvsp[-4].expression).value.integer == FOR_EXPRESSION_ANY))) { (yyval.expression).required_strings.count = 1; } else { (yyval.expression).required_strings.count = 0; } yr_parser_emit(yyscanner, OP_OF_FOUND_IN, NULL); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; } #line 3843 "libyara/grammar.c" break; case 98: /* expression: for_expression "" string_set "" primary_expression */ #line 1849 "libyara/grammar.y" { if ((yyvsp[0].expression).type != EXPRESSION_TYPE_INTEGER) { yr_compiler_set_error_extra_info(compiler, "at expression must be an integer"); fail_with_error(ERROR_INVALID_VALUE); } if ((yyvsp[-4].expression).type == EXPRESSION_TYPE_INTEGER && (yyvsp[-4].expression).value.integer > (yyvsp[-2].integer)) { yywarning(yyscanner, "expression always false - requesting %" PRId64 " of %" PRId64 ".", (yyvsp[-4].expression).value.integer, (yyvsp[-2].integer)); } // Both of these are warnings: // // "N of them at 0" where N > 1 // //"all of them at 0" where there is more than 1 in "them". // // This means you can do "all of them at 0" if you only have one string // defined in the set. if (((yyvsp[-4].expression).type == EXPRESSION_TYPE_INTEGER && !IS_UNDEFINED((yyvsp[-4].expression).value.integer) && (yyvsp[-4].expression).value.integer > 1) || ((yyvsp[-4].expression).type == EXPRESSION_TYPE_QUANTIFIER && (yyvsp[-4].expression).value.integer == FOR_EXPRESSION_ALL && (yyvsp[-2].integer) > 1)) { yywarning(yyscanner, "multiple strings at an offset is usually false."); } if (((yyvsp[-4].expression).type == EXPRESSION_TYPE_INTEGER && (yyvsp[-4].expression).value.integer > 0) || ((yyvsp[-4].expression).type == EXPRESSION_TYPE_QUANTIFIER && ((yyvsp[-4].expression).value.integer == FOR_EXPRESSION_ALL || (yyvsp[-4].expression).value.integer == FOR_EXPRESSION_ANY))) { (yyval.expression).required_strings.count = 1; } else { (yyval.expression).required_strings.count = 0; } yr_parser_emit(yyscanner, OP_OF_FOUND_AT, NULL); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; } #line 3895 "libyara/grammar.c" break; case 99: /* expression: "" boolean_expression */ #line 1897 "libyara/grammar.y" { yr_parser_emit(yyscanner, OP_NOT, NULL); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 3906 "libyara/grammar.c" break; case 100: /* expression: "" boolean_expression */ #line 1904 "libyara/grammar.y" { yr_parser_emit(yyscanner, OP_DEFINED, NULL); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 3916 "libyara/grammar.c" break; case 101: /* $@8: %empty */ #line 1910 "libyara/grammar.y" { YR_FIXUP* fixup; YR_ARENA_REF jmp_offset_ref; fail_if_error(yr_parser_emit_with_arg_int32( yyscanner, OP_JFALSE, 0, // still don't know the jump offset, use 0 for now. NULL, &jmp_offset_ref)); // Create a fixup entry for the jump and push it in the stack. fixup = (YR_FIXUP*) yr_malloc(sizeof(YR_FIXUP)); if (fixup == NULL) fail_with_error(ERROR_INSUFFICIENT_MEMORY); fixup->ref = jmp_offset_ref; fixup->next = compiler->fixup_stack_head; compiler->fixup_stack_head = fixup; } #line 3942 "libyara/grammar.c" break; case 102: /* expression: boolean_expression "" $@8 boolean_expression */ #line 1932 "libyara/grammar.y" { YR_FIXUP* fixup; fail_if_error(yr_parser_emit(yyscanner, OP_AND, NULL)); fixup = compiler->fixup_stack_head; int32_t* jmp_offset_addr = (int32_t*) yr_arena_ref_to_ptr( compiler->arena, &fixup->ref); int32_t jmp_offset = \ yr_arena_get_current_offset(compiler->arena, YR_CODE_SECTION) - fixup->ref.offset + 1; memcpy(jmp_offset_addr, &jmp_offset, sizeof(jmp_offset)); // Remove fixup from the stack. compiler->fixup_stack_head = fixup->next; yr_free(fixup); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = (yyvsp[0].expression).required_strings.count + (yyvsp[-3].expression).required_strings.count; } #line 3970 "libyara/grammar.c" break; case 103: /* $@9: %empty */ #line 1956 "libyara/grammar.y" { YR_FIXUP* fixup; YR_ARENA_REF jmp_offset_ref; fail_if_error(yr_parser_emit_with_arg_int32( yyscanner, OP_JTRUE, 0, // still don't know the jump destination, use 0 for now. NULL, &jmp_offset_ref)); fixup = (YR_FIXUP*) yr_malloc(sizeof(YR_FIXUP)); if (fixup == NULL) fail_with_error(ERROR_INSUFFICIENT_MEMORY); fixup->ref = jmp_offset_ref; fixup->next = compiler->fixup_stack_head; compiler->fixup_stack_head = fixup; } #line 3995 "libyara/grammar.c" break; case 104: /* expression: boolean_expression "" $@9 boolean_expression */ #line 1977 "libyara/grammar.y" { YR_FIXUP* fixup; fail_if_error(yr_parser_emit(yyscanner, OP_OR, NULL)); fixup = compiler->fixup_stack_head; int32_t jmp_offset = \ yr_arena_get_current_offset(compiler->arena, YR_CODE_SECTION) - fixup->ref.offset + 1; int32_t* jmp_offset_addr = (int32_t*) yr_arena_ref_to_ptr( compiler->arena, &fixup->ref); memcpy(jmp_offset_addr, &jmp_offset, sizeof(jmp_offset)); // Remove fixup from the stack. compiler->fixup_stack_head = fixup->next; yr_free(fixup); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; // Set required string count to minimum from both parts if ((yyvsp[-3].expression).required_strings.count > (yyvsp[0].expression).required_strings.count) { (yyval.expression).required_strings.count = (yyvsp[0].expression).required_strings.count; } else { (yyval.expression).required_strings.count = (yyvsp[-3].expression).required_strings.count; } } #line 4029 "libyara/grammar.c" break; case 105: /* expression: primary_expression "<" primary_expression */ #line 2007 "libyara/grammar.y" { fail_if_error(yr_parser_reduce_operation( yyscanner, "<", (yyvsp[-2].expression), (yyvsp[0].expression))); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 4041 "libyara/grammar.c" break; case 106: /* expression: primary_expression ">" primary_expression */ #line 2015 "libyara/grammar.y" { fail_if_error(yr_parser_reduce_operation( yyscanner, ">", (yyvsp[-2].expression), (yyvsp[0].expression))); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 4053 "libyara/grammar.c" break; case 107: /* expression: primary_expression "<=" primary_expression */ #line 2023 "libyara/grammar.y" { fail_if_error(yr_parser_reduce_operation( yyscanner, "<=", (yyvsp[-2].expression), (yyvsp[0].expression))); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 4065 "libyara/grammar.c" break; case 108: /* expression: primary_expression ">=" primary_expression */ #line 2031 "libyara/grammar.y" { fail_if_error(yr_parser_reduce_operation( yyscanner, ">=", (yyvsp[-2].expression), (yyvsp[0].expression))); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 4077 "libyara/grammar.c" break; case 109: /* expression: primary_expression "==" primary_expression */ #line 2039 "libyara/grammar.y" { fail_if_error(yr_parser_reduce_operation( yyscanner, "==", (yyvsp[-2].expression), (yyvsp[0].expression))); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 4089 "libyara/grammar.c" break; case 110: /* expression: primary_expression "!=" primary_expression */ #line 2047 "libyara/grammar.y" { fail_if_error(yr_parser_reduce_operation( yyscanner, "!=", (yyvsp[-2].expression), (yyvsp[0].expression))); (yyval.expression).type = EXPRESSION_TYPE_BOOLEAN; (yyval.expression).required_strings.count = 0; } #line 4101 "libyara/grammar.c" break; case 111: /* expression: primary_expression */ #line 2055 "libyara/grammar.y" { (yyval.expression) = (yyvsp[0].expression); } #line 4109 "libyara/grammar.c" break; case 112: /* expression: '(' expression ')' */ #line 2059 "libyara/grammar.y" { (yyval.expression) = (yyvsp[-1].expression); } #line 4117 "libyara/grammar.c" break; case 113: /* for_iteration: for_variables "" iterator */ #line 2066 "libyara/grammar.y" { (yyval.integer) = FOR_ITERATION_ITERATOR; } #line 4123 "libyara/grammar.c" break; case 114: /* for_iteration: "" string_iterator */ #line 2068 "libyara/grammar.y" { int var_frame; int result = ERROR_SUCCESS; if (compiler->loop_for_of_var_index != -1) result = ERROR_NESTED_FOR_OF_LOOP; fail_if_error(result); // Simulate that we have 1 variable with string loops compiler->loop[compiler->loop_index].vars_count = 1; // Set where we can find our string in case $ is in // the body of the loop var_frame = _yr_compiler_get_var_frame(compiler); compiler->loop_for_of_var_index = var_frame + compiler->loop[compiler->loop_index].vars_internal_count; (yyval.integer) = FOR_ITERATION_STRING_SET; } #line 4148 "libyara/grammar.c" break; case 115: /* for_variables: "identifier" */ #line 2093 "libyara/grammar.y" { int result = ERROR_SUCCESS; YR_LOOP_CONTEXT* loop_ctx = &compiler->loop[compiler->loop_index]; if (yr_parser_lookup_loop_variable(yyscanner, (yyvsp[0].c_string), NULL) >= 0) { yr_compiler_set_error_extra_info(compiler, (yyvsp[0].c_string)); yr_free((yyvsp[0].c_string)); result = ERROR_DUPLICATED_LOOP_IDENTIFIER; } fail_if_error(result); loop_ctx->vars[loop_ctx->vars_count++].identifier.ptr = (yyvsp[0].c_string); assert(loop_ctx->vars_count <= YR_MAX_LOOP_VARS); } #line 4172 "libyara/grammar.c" break; case 116: /* for_variables: for_variables ',' "identifier" */ #line 2113 "libyara/grammar.y" { int result = ERROR_SUCCESS; YR_LOOP_CONTEXT* loop_ctx = &compiler->loop[compiler->loop_index]; if (loop_ctx->vars_count == YR_MAX_LOOP_VARS) { yr_compiler_set_error_extra_info(compiler, "too many loop variables"); yr_free((yyvsp[0].c_string)); result = ERROR_SYNTAX_ERROR; } else if (yr_parser_lookup_loop_variable(yyscanner, (yyvsp[0].c_string), NULL) >= 0) { yr_compiler_set_error_extra_info(compiler, (yyvsp[0].c_string)); yr_free((yyvsp[0].c_string)); result = ERROR_DUPLICATED_LOOP_IDENTIFIER; } fail_if_error(result); loop_ctx->vars[loop_ctx->vars_count++].identifier.ptr = (yyvsp[0].c_string); } #line 4201 "libyara/grammar.c" break; case 117: /* iterator: identifier */ #line 2141 "libyara/grammar.y" { YR_LOOP_CONTEXT* loop_ctx = &compiler->loop[compiler->loop_index]; // Initially we assume that the identifier is from a non-iterable type, // this will change later if it's iterable. int result = ERROR_WRONG_TYPE; if ((yyvsp[0].expression).type == EXPRESSION_TYPE_OBJECT) { switch((yyvsp[0].expression).value.object->type) { case OBJECT_TYPE_ARRAY: // If iterating an array the loop must define a single variable // that will hold the current item. If a different number of // variables were defined that's an error. if (loop_ctx->vars_count == 1) { loop_ctx->vars[0].type = EXPRESSION_TYPE_OBJECT; loop_ctx->vars[0].value.object = \ object_as_array((yyvsp[0].expression).value.object)->prototype_item; result = yr_parser_emit(yyscanner, OP_ITER_START_ARRAY, NULL); } else { yr_compiler_set_error_extra_info_fmt( compiler, "iterator for \"%s\" yields a single item on each iteration" ", but the loop expects %d", expression_identifier((yyvsp[0].expression)), loop_ctx->vars_count); result = ERROR_SYNTAX_ERROR; } break; case OBJECT_TYPE_DICTIONARY: // If iterating a dictionary the loop must define exactly two // variables, one for the key and another for the value . If a // different number of variables were defined that's an error. if (loop_ctx->vars_count == 2) { loop_ctx->vars[0].type = EXPRESSION_TYPE_STRING; loop_ctx->vars[0].value.sized_string_ref = YR_ARENA_NULL_REF; loop_ctx->vars[1].type = EXPRESSION_TYPE_OBJECT; loop_ctx->vars[1].value.object = \ object_as_array((yyvsp[0].expression).value.object)->prototype_item; result = yr_parser_emit(yyscanner, OP_ITER_START_DICT, NULL); } else { yr_compiler_set_error_extra_info_fmt( compiler, "iterator for \"%s\" yields a key,value pair item on each iteration", expression_identifier((yyvsp[0].expression))); result = ERROR_SYNTAX_ERROR; } break; } } if (result == ERROR_WRONG_TYPE) { yr_compiler_set_error_extra_info_fmt( compiler, "identifier \"%s\" is not iterable", expression_identifier((yyvsp[0].expression))); } fail_if_error(result); } #line 4279 "libyara/grammar.c" break; case 118: /* iterator: set */ #line 2215 "libyara/grammar.y" { int result = ERROR_SUCCESS; YR_LOOP_CONTEXT* loop_ctx = &compiler->loop[compiler->loop_index]; if (loop_ctx->vars_count == 1) { loop_ctx->vars[0].type = (yyvsp[0].enumeration).type; if ((yyvsp[0].enumeration).type == EXPRESSION_TYPE_STRING) loop_ctx->vars[0].value.sized_string_ref = YR_ARENA_NULL_REF; else loop_ctx->vars[0].value.integer = YR_UNDEFINED; } else { yr_compiler_set_error_extra_info_fmt( compiler, "iterator yields one value on each iteration " ", but the loop expects %d", loop_ctx->vars_count); result = ERROR_SYNTAX_ERROR; } fail_if_error(result); } #line 4311 "libyara/grammar.c" break; case 119: /* set: '(' enumeration ')' */ #line 2247 "libyara/grammar.y" { // $2.count contains the number of items in the enumeration fail_if_error(yr_parser_emit_push_const(yyscanner, (yyvsp[-1].enumeration).count)); if ((yyvsp[-1].enumeration).type == EXPRESSION_TYPE_INTEGER) { fail_if_error(yr_parser_emit( yyscanner, OP_ITER_START_INT_ENUM, NULL)); } else { fail_if_error(yr_parser_emit( yyscanner, OP_ITER_START_TEXT_STRING_SET, NULL)); } (yyval.enumeration).type = (yyvsp[-1].enumeration).type; } #line 4333 "libyara/grammar.c" break; case 120: /* set: range */ #line 2265 "libyara/grammar.y" { fail_if_error(yr_parser_emit( yyscanner, OP_ITER_START_INT_RANGE, NULL)); (yyval.enumeration).type = EXPRESSION_TYPE_INTEGER; } #line 4344 "libyara/grammar.c" break; case 121: /* range: '(' primary_expression ".." primary_expression ')' */ #line 2276 "libyara/grammar.y" { int result = ERROR_SUCCESS; if ((yyvsp[-3].expression).type != EXPRESSION_TYPE_INTEGER) { yr_compiler_set_error_extra_info( compiler, "wrong type for range's lower bound"); result = ERROR_WRONG_TYPE; } if ((yyvsp[-1].expression).type != EXPRESSION_TYPE_INTEGER) { yr_compiler_set_error_extra_info( compiler, "wrong type for range's upper bound"); result = ERROR_WRONG_TYPE; } // If we can statically determine lower and upper bounds, ensure // lower < upper. Check for upper bound here because some things (like // string count) are EXPRESSION_TYPE_INTEGER. if ((yyvsp[-3].expression).value.integer != YR_UNDEFINED && (yyvsp[-1].expression).value.integer != YR_UNDEFINED) { if ((yyvsp[-3].expression).value.integer > (yyvsp[-1].expression).value.integer) { yr_compiler_set_error_extra_info( compiler, "range lower bound must be less than upper bound"); result = ERROR_INVALID_VALUE; } else if ((yyvsp[-3].expression).value.integer < 0) { yr_compiler_set_error_extra_info( compiler, "range lower bound can not be negative"); result = ERROR_INVALID_VALUE; } } fail_if_error(result); } #line 4387 "libyara/grammar.c" break; case 122: /* enumeration: primary_expression */ #line 2319 "libyara/grammar.y" { int result = ERROR_SUCCESS; if ((yyvsp[0].expression).type != EXPRESSION_TYPE_INTEGER && (yyvsp[0].expression).type != EXPRESSION_TYPE_STRING) { yr_compiler_set_error_extra_info( compiler, "wrong type for enumeration item"); result = ERROR_WRONG_TYPE; } fail_if_error(result); (yyval.enumeration).type = (yyvsp[0].expression).type; (yyval.enumeration).count = 1; } #line 4407 "libyara/grammar.c" break; case 123: /* enumeration: enumeration ',' primary_expression */ #line 2335 "libyara/grammar.y" { int result = ERROR_SUCCESS; if ((yyvsp[0].expression).type != (yyvsp[-2].enumeration).type) { yr_compiler_set_error_extra_info( compiler, "enumerations must be all the same type"); result = ERROR_WRONG_TYPE; } fail_if_error(result); (yyval.enumeration).type = (yyvsp[-2].enumeration).type; (yyval.enumeration).count = (yyvsp[-2].enumeration).count + 1; } #line 4427 "libyara/grammar.c" break; case 124: /* string_iterator: string_set */ #line 2355 "libyara/grammar.y" { fail_if_error(yr_parser_emit_push_const(yyscanner, (yyvsp[0].integer))); fail_if_error(yr_parser_emit(yyscanner, OP_ITER_START_STRING_SET, NULL)); } #line 4437 "libyara/grammar.c" break; case 125: /* $@10: %empty */ #line 2364 "libyara/grammar.y" { // Push end-of-list marker yr_parser_emit_push_const(yyscanner, YR_UNDEFINED); } #line 4446 "libyara/grammar.c" break; case 126: /* string_set: '(' $@10 string_enumeration ')' */ #line 2369 "libyara/grammar.y" { (yyval.integer) = (yyvsp[-1].integer); } #line 4454 "libyara/grammar.c" break; case 127: /* string_set: "" */ #line 2373 "libyara/grammar.y" { fail_if_error(yr_parser_emit_push_const(yyscanner, YR_UNDEFINED)); int count = 0; fail_if_error(yr_parser_emit_pushes_for_strings( yyscanner, "$*", &count)); (yyval.integer) = count; } #line 4468 "libyara/grammar.c" break; case 128: /* string_enumeration: string_enumeration_item */ #line 2386 "libyara/grammar.y" { (yyval.integer) = (yyvsp[0].integer); } #line 4474 "libyara/grammar.c" break; case 129: /* string_enumeration: string_enumeration ',' string_enumeration_item */ #line 2387 "libyara/grammar.y" { (yyval.integer) = (yyvsp[-2].integer) + (yyvsp[0].integer); } #line 4480 "libyara/grammar.c" break; case 130: /* string_enumeration_item: "string identifier" */ #line 2393 "libyara/grammar.y" { int count = 0; int result = yr_parser_emit_pushes_for_strings(yyscanner, (yyvsp[0].c_string), &count); yr_free((yyvsp[0].c_string)); fail_if_error(result); (yyval.integer) = count; } #line 4494 "libyara/grammar.c" break; case 131: /* string_enumeration_item: "string identifier with wildcard" */ #line 2403 "libyara/grammar.y" { int count = 0; int result = yr_parser_emit_pushes_for_strings(yyscanner, (yyvsp[0].c_string), &count); yr_free((yyvsp[0].c_string)); fail_if_error(result); (yyval.integer) = count; } #line 4508 "libyara/grammar.c" break; case 132: /* $@11: %empty */ #line 2417 "libyara/grammar.y" { // Push end-of-list marker yr_parser_emit_push_const(yyscanner, YR_UNDEFINED); } #line 4517 "libyara/grammar.c" break; case 133: /* rule_set: '(' $@11 rule_enumeration ')' */ #line 2422 "libyara/grammar.y" { (yyval.integer) = (yyvsp[-1].integer); } #line 4525 "libyara/grammar.c" break; case 134: /* rule_enumeration: rule_enumeration_item */ #line 2429 "libyara/grammar.y" { (yyval.integer) = (yyvsp[0].integer); } #line 4531 "libyara/grammar.c" break; case 135: /* rule_enumeration: rule_enumeration ',' rule_enumeration_item */ #line 2430 "libyara/grammar.y" { (yyval.integer) = (yyvsp[-2].integer) + (yyvsp[0].integer); } #line 4537 "libyara/grammar.c" break; case 136: /* rule_enumeration_item: "identifier" */ #line 2436 "libyara/grammar.y" { int result = ERROR_SUCCESS; YR_NAMESPACE* ns = (YR_NAMESPACE*) yr_arena_get_ptr( compiler->arena, YR_NAMESPACES_TABLE, compiler->current_namespace_idx * sizeof(struct YR_NAMESPACE)); uint32_t rule_idx = yr_hash_table_lookup_uint32( compiler->rules_table, (yyvsp[0].c_string), ns->name); if (rule_idx != UINT32_MAX) { result = yr_parser_emit_with_arg( yyscanner, OP_PUSH_RULE, rule_idx, NULL, NULL); } else { yr_compiler_set_error_extra_info(compiler, (yyvsp[0].c_string)); result = ERROR_UNDEFINED_IDENTIFIER; } yr_free((yyvsp[0].c_string)); fail_if_error(result); (yyval.integer) = 1; } #line 4574 "libyara/grammar.c" break; case 137: /* rule_enumeration_item: "identifier" '*' */ #line 2469 "libyara/grammar.y" { int count = 0; YR_NAMESPACE* ns = (YR_NAMESPACE*) yr_arena_get_ptr( compiler->arena, YR_NAMESPACES_TABLE, compiler->current_namespace_idx * sizeof(struct YR_NAMESPACE)); yr_hash_table_add_uint32( compiler->wildcard_identifiers_table, (yyvsp[-1].c_string), ns->name, 1); int result = yr_parser_emit_pushes_for_rules(yyscanner, (yyvsp[-1].c_string), &count); yr_free((yyvsp[-1].c_string)); fail_if_error(result); (yyval.integer) = count; } #line 4599 "libyara/grammar.c" break; case 138: /* for_expression: primary_expression */ #line 2494 "libyara/grammar.y" { if ((yyvsp[0].expression).type == EXPRESSION_TYPE_INTEGER && !IS_UNDEFINED((yyvsp[0].expression).value.integer)) { if ((yyvsp[0].expression).value.integer == 0) { yywarning(yyscanner, "consider using \"none\" keyword, it is less ambiguous."); } if ((yyvsp[0].expression).value.integer < 0) { yr_compiler_set_error_extra_info_fmt(compiler, "%" PRId64, (yyvsp[0].expression).value.integer); fail_with_error(ERROR_INVALID_VALUE); } } if ((yyvsp[0].expression).type == EXPRESSION_TYPE_FLOAT) { yr_compiler_set_error_extra_info_fmt(compiler, "%a", (yyvsp[0].expression).value.double_); fail_with_error(ERROR_INVALID_VALUE); } if ((yyvsp[0].expression).type == EXPRESSION_TYPE_STRING) { SIZED_STRING* ss = yr_arena_ref_to_ptr(compiler->arena, &(yyvsp[0].expression).value.sized_string_ref); // If the expression is an external string variable we need to get // it some other way. if (ss != NULL) { yr_compiler_set_error_extra_info_fmt(compiler, "%s", ss->c_string); } else { yr_compiler_set_error_extra_info(compiler, "string in for_expression is invalid"); } fail_with_error(ERROR_INVALID_VALUE); } if ((yyvsp[0].expression).type == EXPRESSION_TYPE_REGEXP) { yr_compiler_set_error_extra_info(compiler, "regexp in for_expression is invalid"); fail_with_error(ERROR_INVALID_VALUE); } (yyval.expression).value.integer = (yyvsp[0].expression).value.integer; } #line 4659 "libyara/grammar.c" break; case 139: /* for_expression: for_quantifier */ #line 2550 "libyara/grammar.y" { (yyval.expression).value.integer = (yyvsp[0].expression).value.integer; } #line 4667 "libyara/grammar.c" break; case 140: /* for_quantifier: "" */ #line 2557 "libyara/grammar.y" { yr_parser_emit_push_const(yyscanner, YR_UNDEFINED); (yyval.expression).type = EXPRESSION_TYPE_QUANTIFIER; (yyval.expression).value.integer = FOR_EXPRESSION_ALL; } #line 4677 "libyara/grammar.c" break; case 141: /* for_quantifier: "" */ #line 2563 "libyara/grammar.y" { yr_parser_emit_push_const(yyscanner, 1); (yyval.expression).type = EXPRESSION_TYPE_QUANTIFIER; (yyval.expression).value.integer = FOR_EXPRESSION_ANY; } #line 4687 "libyara/grammar.c" break; case 142: /* for_quantifier: "" */ #line 2569 "libyara/grammar.y" { yr_parser_emit_push_const(yyscanner, 0); (yyval.expression).type = EXPRESSION_TYPE_QUANTIFIER; (yyval.expression).value.integer = FOR_EXPRESSION_NONE; } #line 4697 "libyara/grammar.c" break; case 143: /* primary_expression: '(' primary_expression ')' */ #line 2579 "libyara/grammar.y" { (yyval.expression) = (yyvsp[-1].expression); } #line 4705 "libyara/grammar.c" break; case 144: /* primary_expression: "" */ #line 2583 "libyara/grammar.y" { fail_if_error(yr_parser_emit( yyscanner, OP_FILESIZE, NULL)); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; (yyval.expression).value.integer = YR_UNDEFINED; } #line 4717 "libyara/grammar.c" break; case 145: /* primary_expression: "" */ #line 2591 "libyara/grammar.y" { yywarning(yyscanner, "using deprecated \"entrypoint\" keyword. Use the \"entry_point\" " "function from PE module instead."); fail_if_error(yr_parser_emit( yyscanner, OP_ENTRYPOINT, NULL)); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; (yyval.expression).value.integer = YR_UNDEFINED; } #line 4733 "libyara/grammar.c" break; case 146: /* primary_expression: "integer function" '(' primary_expression ')' */ #line 2603 "libyara/grammar.y" { check_type((yyvsp[-1].expression), EXPRESSION_TYPE_INTEGER, "intXXXX or uintXXXX"); // _INTEGER_FUNCTION_ could be any of int8, int16, int32, uint8, // uint32, etc. $1 contains an index that added to OP_READ_INT results // in the proper OP_INTXX opcode. fail_if_error(yr_parser_emit( yyscanner, (uint8_t) (OP_READ_INT + (yyvsp[-3].integer)), NULL)); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; (yyval.expression).value.integer = YR_UNDEFINED; } #line 4751 "libyara/grammar.c" break; case 147: /* primary_expression: "integer number" */ #line 2617 "libyara/grammar.y" { fail_if_error(yr_parser_emit_push_const(yyscanner, (yyvsp[0].integer))); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; (yyval.expression).value.integer = (yyvsp[0].integer); } #line 4762 "libyara/grammar.c" break; case 148: /* primary_expression: "floating point number" */ #line 2624 "libyara/grammar.y" { fail_if_error(yr_parser_emit_with_arg_double( yyscanner, OP_PUSH, (yyvsp[0].double_), NULL, NULL)); (yyval.expression).type = EXPRESSION_TYPE_FLOAT; } #line 4773 "libyara/grammar.c" break; case 149: /* primary_expression: "text string" */ #line 2631 "libyara/grammar.y" { YR_ARENA_REF ref; int result = _yr_compiler_store_data( compiler, (yyvsp[0].sized_string), (yyvsp[0].sized_string)->length + sizeof(SIZED_STRING), &ref); yr_free((yyvsp[0].sized_string)); if (result == ERROR_SUCCESS) result = yr_parser_emit_with_arg_reloc( yyscanner, OP_PUSH, yr_arena_ref_to_ptr(compiler->arena, &ref), NULL, NULL); fail_if_error(result); (yyval.expression).type = EXPRESSION_TYPE_STRING; (yyval.expression).value.sized_string_ref = ref; } #line 4802 "libyara/grammar.c" break; case 150: /* primary_expression: "string count" "" range */ #line 2656 "libyara/grammar.y" { int result = yr_parser_reduce_string_identifier( yyscanner, (yyvsp[-2].c_string), OP_COUNT_IN, YR_UNDEFINED); yr_free((yyvsp[-2].c_string)); fail_if_error(result); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; (yyval.expression).value.integer = YR_UNDEFINED; } #line 4818 "libyara/grammar.c" break; case 151: /* primary_expression: "string count" */ #line 2668 "libyara/grammar.y" { int result = yr_parser_reduce_string_identifier( yyscanner, (yyvsp[0].c_string), OP_COUNT, YR_UNDEFINED); yr_free((yyvsp[0].c_string)); fail_if_error(result); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; (yyval.expression).value.integer = YR_UNDEFINED; } #line 4834 "libyara/grammar.c" break; case 152: /* primary_expression: "string offset" '[' primary_expression ']' */ #line 2680 "libyara/grammar.y" { int result = yr_parser_reduce_string_identifier( yyscanner, (yyvsp[-3].c_string), OP_OFFSET, YR_UNDEFINED); yr_free((yyvsp[-3].c_string)); fail_if_error(result); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; (yyval.expression).value.integer = YR_UNDEFINED; } #line 4850 "libyara/grammar.c" break; case 153: /* primary_expression: "string offset" */ #line 2692 "libyara/grammar.y" { int result = yr_parser_emit_push_const(yyscanner, 1); if (result == ERROR_SUCCESS) result = yr_parser_reduce_string_identifier( yyscanner, (yyvsp[0].c_string), OP_OFFSET, YR_UNDEFINED); yr_free((yyvsp[0].c_string)); fail_if_error(result); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; (yyval.expression).value.integer = YR_UNDEFINED; } #line 4869 "libyara/grammar.c" break; case 154: /* primary_expression: "string length" '[' primary_expression ']' */ #line 2707 "libyara/grammar.y" { int result = yr_parser_reduce_string_identifier( yyscanner, (yyvsp[-3].c_string), OP_LENGTH, YR_UNDEFINED); yr_free((yyvsp[-3].c_string)); fail_if_error(result); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; (yyval.expression).value.integer = YR_UNDEFINED; } #line 4885 "libyara/grammar.c" break; case 155: /* primary_expression: "string length" */ #line 2719 "libyara/grammar.y" { int result = yr_parser_emit_push_const(yyscanner, 1); if (result == ERROR_SUCCESS) result = yr_parser_reduce_string_identifier( yyscanner, (yyvsp[0].c_string), OP_LENGTH, YR_UNDEFINED); yr_free((yyvsp[0].c_string)); fail_if_error(result); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; (yyval.expression).value.integer = YR_UNDEFINED; } #line 4904 "libyara/grammar.c" break; case 156: /* primary_expression: identifier */ #line 2734 "libyara/grammar.y" { int result = ERROR_SUCCESS; if ((yyvsp[0].expression).type == EXPRESSION_TYPE_OBJECT) { result = yr_parser_emit( yyscanner, OP_OBJ_VALUE, NULL); switch((yyvsp[0].expression).value.object->type) { case OBJECT_TYPE_INTEGER: (yyval.expression).type = EXPRESSION_TYPE_INTEGER; (yyval.expression).value.integer = (yyvsp[0].expression).value.object->value.i; break; case OBJECT_TYPE_FLOAT: (yyval.expression).type = EXPRESSION_TYPE_FLOAT; break; case OBJECT_TYPE_STRING: (yyval.expression).type = EXPRESSION_TYPE_STRING; (yyval.expression).value.sized_string_ref = YR_ARENA_NULL_REF; break; default: // In a primary expression any identifier that corresponds to an // object must be of type integer, float or string. If "foobar" is // either a function, structure, dictionary or array you can not // use it as: // condition: foobar yr_compiler_set_error_extra_info_fmt( compiler, "wrong usage of identifier \"%s\"", expression_identifier((yyvsp[0].expression))); result = ERROR_WRONG_TYPE; } } else { (yyval.expression) = (yyvsp[0].expression); } fail_if_error(result); } #line 4951 "libyara/grammar.c" break; case 157: /* primary_expression: '-' primary_expression */ #line 2777 "libyara/grammar.y" { int result = ERROR_SUCCESS; check_type((yyvsp[0].expression), EXPRESSION_TYPE_INTEGER | EXPRESSION_TYPE_FLOAT, "-"); if ((yyvsp[0].expression).type == EXPRESSION_TYPE_INTEGER) { (yyval.expression).type = EXPRESSION_TYPE_INTEGER; (yyval.expression).value.integer = ((yyvsp[0].expression).value.integer == YR_UNDEFINED) ? YR_UNDEFINED : -((yyvsp[0].expression).value.integer); result = yr_parser_emit(yyscanner, OP_INT_MINUS, NULL); } else if ((yyvsp[0].expression).type == EXPRESSION_TYPE_FLOAT) { (yyval.expression).type = EXPRESSION_TYPE_FLOAT; result = yr_parser_emit(yyscanner, OP_DBL_MINUS, NULL); } fail_if_error(result); } #line 4976 "libyara/grammar.c" break; case 158: /* primary_expression: primary_expression '+' primary_expression */ #line 2798 "libyara/grammar.y" { int result = yr_parser_reduce_operation( yyscanner, "+", (yyvsp[-2].expression), (yyvsp[0].expression)); if ((yyvsp[-2].expression).type == EXPRESSION_TYPE_INTEGER && (yyvsp[0].expression).type == EXPRESSION_TYPE_INTEGER) { int64_t i1 = (yyvsp[-2].expression).value.integer; int64_t i2 = (yyvsp[0].expression).value.integer; if (!IS_UNDEFINED(i1) && !IS_UNDEFINED(i2) && ( (i2 > 0 && i1 > INT64_MAX - i2) || (i2 < 0 && i1 < INT64_MIN - i2) )) { yr_compiler_set_error_extra_info_fmt( compiler, "%" PRId64 " + %" PRId64, i1, i2); result = ERROR_INTEGER_OVERFLOW; } else { (yyval.expression).value.integer = OPERATION(+, i1, i2); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; } } else { (yyval.expression).type = EXPRESSION_TYPE_FLOAT; } fail_if_error(result); } #line 5015 "libyara/grammar.c" break; case 159: /* primary_expression: primary_expression '-' primary_expression */ #line 2833 "libyara/grammar.y" { int result = yr_parser_reduce_operation( yyscanner, "-", (yyvsp[-2].expression), (yyvsp[0].expression)); if ((yyvsp[-2].expression).type == EXPRESSION_TYPE_INTEGER && (yyvsp[0].expression).type == EXPRESSION_TYPE_INTEGER) { int64_t i1 = (yyvsp[-2].expression).value.integer; int64_t i2 = (yyvsp[0].expression).value.integer; if (!IS_UNDEFINED(i1) && !IS_UNDEFINED(i2) && ( (i2 < 0 && i1 > INT64_MAX + i2) || (i2 > 0 && i1 < INT64_MIN + i2) )) { yr_compiler_set_error_extra_info_fmt( compiler, "%" PRId64 " - %" PRId64, i1, i2); result = ERROR_INTEGER_OVERFLOW; } else { (yyval.expression).value.integer = OPERATION(-, i1, i2); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; } } else { (yyval.expression).type = EXPRESSION_TYPE_FLOAT; } fail_if_error(result); } #line 5054 "libyara/grammar.c" break; case 160: /* primary_expression: primary_expression '*' primary_expression */ #line 2868 "libyara/grammar.y" { int result = yr_parser_reduce_operation( yyscanner, "*", (yyvsp[-2].expression), (yyvsp[0].expression)); if ((yyvsp[-2].expression).type == EXPRESSION_TYPE_INTEGER && (yyvsp[0].expression).type == EXPRESSION_TYPE_INTEGER) { int64_t i1 = (yyvsp[-2].expression).value.integer; int64_t i2 = (yyvsp[0].expression).value.integer; if (!IS_UNDEFINED(i1) && !IS_UNDEFINED(i2) && ( i2 != 0 && llabs(i1) > INT64_MAX / llabs(i2) )) { yr_compiler_set_error_extra_info_fmt( compiler, "%" PRId64 " * %" PRId64, i1, i2); result = ERROR_INTEGER_OVERFLOW; } else { (yyval.expression).value.integer = OPERATION(*, i1, i2); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; } } else { (yyval.expression).type = EXPRESSION_TYPE_FLOAT; } fail_if_error(result); } #line 5092 "libyara/grammar.c" break; case 161: /* primary_expression: primary_expression '\\' primary_expression */ #line 2902 "libyara/grammar.y" { int result = yr_parser_reduce_operation( yyscanner, "\\", (yyvsp[-2].expression), (yyvsp[0].expression)); if ((yyvsp[-2].expression).type == EXPRESSION_TYPE_INTEGER && (yyvsp[0].expression).type == EXPRESSION_TYPE_INTEGER) { if ((yyvsp[0].expression).value.integer != 0) { (yyval.expression).value.integer = OPERATION(/, (yyvsp[-2].expression).value.integer, (yyvsp[0].expression).value.integer); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; } else { result = ERROR_DIVISION_BY_ZERO; } } else { (yyval.expression).type = EXPRESSION_TYPE_FLOAT; } fail_if_error(result); } #line 5121 "libyara/grammar.c" break; case 162: /* primary_expression: primary_expression '%' primary_expression */ #line 2927 "libyara/grammar.y" { check_type((yyvsp[-2].expression), EXPRESSION_TYPE_INTEGER, "%"); check_type((yyvsp[0].expression), EXPRESSION_TYPE_INTEGER, "%"); fail_if_error(yr_parser_emit(yyscanner, OP_MOD, NULL)); if ((yyvsp[0].expression).value.integer != 0) { (yyval.expression).value.integer = OPERATION(%, (yyvsp[-2].expression).value.integer, (yyvsp[0].expression).value.integer); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; } else { fail_if_error(ERROR_DIVISION_BY_ZERO); } } #line 5142 "libyara/grammar.c" break; case 163: /* primary_expression: primary_expression '^' primary_expression */ #line 2944 "libyara/grammar.y" { check_type((yyvsp[-2].expression), EXPRESSION_TYPE_INTEGER, "^"); check_type((yyvsp[0].expression), EXPRESSION_TYPE_INTEGER, "^"); fail_if_error(yr_parser_emit(yyscanner, OP_BITWISE_XOR, NULL)); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; (yyval.expression).value.integer = OPERATION(^, (yyvsp[-2].expression).value.integer, (yyvsp[0].expression).value.integer); } #line 5156 "libyara/grammar.c" break; case 164: /* primary_expression: primary_expression '&' primary_expression */ #line 2954 "libyara/grammar.y" { check_type((yyvsp[-2].expression), EXPRESSION_TYPE_INTEGER, "^"); check_type((yyvsp[0].expression), EXPRESSION_TYPE_INTEGER, "^"); fail_if_error(yr_parser_emit(yyscanner, OP_BITWISE_AND, NULL)); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; (yyval.expression).value.integer = OPERATION(&, (yyvsp[-2].expression).value.integer, (yyvsp[0].expression).value.integer); } #line 5170 "libyara/grammar.c" break; case 165: /* primary_expression: primary_expression '|' primary_expression */ #line 2964 "libyara/grammar.y" { check_type((yyvsp[-2].expression), EXPRESSION_TYPE_INTEGER, "|"); check_type((yyvsp[0].expression), EXPRESSION_TYPE_INTEGER, "|"); fail_if_error(yr_parser_emit(yyscanner, OP_BITWISE_OR, NULL)); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; (yyval.expression).value.integer = OPERATION(|, (yyvsp[-2].expression).value.integer, (yyvsp[0].expression).value.integer); } #line 5184 "libyara/grammar.c" break; case 166: /* primary_expression: '~' primary_expression */ #line 2974 "libyara/grammar.y" { check_type((yyvsp[0].expression), EXPRESSION_TYPE_INTEGER, "~"); fail_if_error(yr_parser_emit(yyscanner, OP_BITWISE_NOT, NULL)); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; (yyval.expression).value.integer = ((yyvsp[0].expression).value.integer == YR_UNDEFINED) ? YR_UNDEFINED : ~((yyvsp[0].expression).value.integer); } #line 5198 "libyara/grammar.c" break; case 167: /* primary_expression: primary_expression "<<" primary_expression */ #line 2984 "libyara/grammar.y" { int result; check_type((yyvsp[-2].expression), EXPRESSION_TYPE_INTEGER, "<<"); check_type((yyvsp[0].expression), EXPRESSION_TYPE_INTEGER, "<<"); result = yr_parser_emit(yyscanner, OP_SHL, NULL); if (!IS_UNDEFINED((yyvsp[0].expression).value.integer) && (yyvsp[0].expression).value.integer < 0) result = ERROR_INVALID_OPERAND; else if (!IS_UNDEFINED((yyvsp[0].expression).value.integer) && (yyvsp[0].expression).value.integer >= 64) (yyval.expression).value.integer = 0; else (yyval.expression).value.integer = OPERATION(<<, (yyvsp[-2].expression).value.integer, (yyvsp[0].expression).value.integer); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; fail_if_error(result); } #line 5222 "libyara/grammar.c" break; case 168: /* primary_expression: primary_expression ">>" primary_expression */ #line 3004 "libyara/grammar.y" { int result; check_type((yyvsp[-2].expression), EXPRESSION_TYPE_INTEGER, ">>"); check_type((yyvsp[0].expression), EXPRESSION_TYPE_INTEGER, ">>"); result = yr_parser_emit(yyscanner, OP_SHR, NULL); if (!IS_UNDEFINED((yyvsp[0].expression).value.integer) && (yyvsp[0].expression).value.integer < 0) result = ERROR_INVALID_OPERAND; else if (!IS_UNDEFINED((yyvsp[0].expression).value.integer) && (yyvsp[0].expression).value.integer >= 64) (yyval.expression).value.integer = 0; else (yyval.expression).value.integer = OPERATION(<<, (yyvsp[-2].expression).value.integer, (yyvsp[0].expression).value.integer); (yyval.expression).type = EXPRESSION_TYPE_INTEGER; fail_if_error(result); } #line 5246 "libyara/grammar.c" break; case 169: /* primary_expression: regexp */ #line 3024 "libyara/grammar.y" { (yyval.expression) = (yyvsp[0].expression); } #line 5254 "libyara/grammar.c" break; #line 5258 "libyara/grammar.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; *++yyvsp = yyval; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ { const int yylhs = yyr1[yyn] - YYNTOKENS; const int yyi = yypgoto[yylhs] + *yyssp; yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp ? yytable[yyi] : yydefgoto[yylhs]); } goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; { yypcontext_t yyctx = {yyssp, yytoken}; char const *yymsgp = YY_("syntax error"); int yysyntax_error_status; yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx); if (yysyntax_error_status == 0) yymsgp = yymsg; else if (yysyntax_error_status == -1) { if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = YY_CAST (char *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, yymsg_alloc))); if (yymsg) { yysyntax_error_status = yysyntax_error (&yymsg_alloc, &yymsg, &yyctx); yymsgp = yymsg; } else { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; yysyntax_error_status = YYENOMEM; } } yyerror (yyscanner, compiler, yymsgp); if (yysyntax_error_status == YYENOMEM) YYNOMEM; } } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= _END_OF_FILE_) { /* Return failure if at end of input. */ if (yychar == _END_OF_FILE_) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval, yyscanner, compiler); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (0) YYERROR; ++yynerrs; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ /* Pop stack until we find a state that shifts the error token. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYSYMBOL_YYerror; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", YY_ACCESSING_SYMBOL (yystate), yyvsp, yyscanner, compiler); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturnlab; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturnlab; /*-----------------------------------------------------------. | yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | `-----------------------------------------------------------*/ yyexhaustedlab: yyerror (yyscanner, compiler, YY_("memory exhausted")); yyresult = 2; goto yyreturnlab; /*----------------------------------------------------------. | yyreturnlab -- parsing is finished, clean up and return. | `----------------------------------------------------------*/ yyreturnlab: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval, yyscanner, compiler); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yyscanner, compiler); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); return yyresult; } #line 3029 "libyara/grammar.y" yara-4.5.3/libyara/grammar.h000066400000000000000000000167451501365277300157270ustar00rootroot00000000000000/* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison interface for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. 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 . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ #ifndef YY_YARA_YY_LIBYARA_GRAMMAR_H_INCLUDED # define YY_YARA_YY_LIBYARA_GRAMMAR_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yara_yydebug; #endif /* Token kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, _END_OF_FILE_ = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ _END_OF_INCLUDED_FILE_ = 258, /* "end of included file" */ _DOT_DOT_ = 259, /* ".." */ _RULE_ = 260, /* "" */ _PRIVATE_ = 261, /* "" */ _GLOBAL_ = 262, /* "" */ _META_ = 263, /* "" */ _STRINGS_ = 264, /* "" */ _CONDITION_ = 265, /* "" */ _IDENTIFIER_ = 266, /* "identifier" */ _STRING_IDENTIFIER_ = 267, /* "string identifier" */ _STRING_COUNT_ = 268, /* "string count" */ _STRING_OFFSET_ = 269, /* "string offset" */ _STRING_LENGTH_ = 270, /* "string length" */ _STRING_IDENTIFIER_WITH_WILDCARD_ = 271, /* "string identifier with wildcard" */ _NUMBER_ = 272, /* "integer number" */ _DOUBLE_ = 273, /* "floating point number" */ _INTEGER_FUNCTION_ = 274, /* "integer function" */ _TEXT_STRING_ = 275, /* "text string" */ _HEX_STRING_ = 276, /* "hex string" */ _REGEXP_ = 277, /* "regular expression" */ _ASCII_ = 278, /* "" */ _WIDE_ = 279, /* "" */ _XOR_ = 280, /* "" */ _BASE64_ = 281, /* "" */ _BASE64_WIDE_ = 282, /* "" */ _NOCASE_ = 283, /* "" */ _FULLWORD_ = 284, /* "" */ _AT_ = 285, /* "" */ _FILESIZE_ = 286, /* "" */ _ENTRYPOINT_ = 287, /* "" */ _ALL_ = 288, /* "" */ _ANY_ = 289, /* "" */ _NONE_ = 290, /* "" */ _IN_ = 291, /* "" */ _OF_ = 292, /* "" */ _FOR_ = 293, /* "" */ _THEM_ = 294, /* "" */ _MATCHES_ = 295, /* "" */ _CONTAINS_ = 296, /* "" */ _STARTSWITH_ = 297, /* "" */ _ENDSWITH_ = 298, /* "" */ _ICONTAINS_ = 299, /* "" */ _ISTARTSWITH_ = 300, /* "" */ _IENDSWITH_ = 301, /* "" */ _IEQUALS_ = 302, /* "" */ _IMPORT_ = 303, /* "" */ _TRUE_ = 304, /* "" */ _FALSE_ = 305, /* "" */ _OR_ = 306, /* "" */ _AND_ = 307, /* "" */ _NOT_ = 308, /* "" */ _DEFINED_ = 309, /* "" */ _EQ_ = 310, /* "==" */ _NEQ_ = 311, /* "!=" */ _LT_ = 312, /* "<" */ _LE_ = 313, /* "<=" */ _GT_ = 314, /* ">" */ _GE_ = 315, /* ">=" */ _SHIFT_LEFT_ = 316, /* "<<" */ _SHIFT_RIGHT_ = 317, /* ">>" */ UNARY_MINUS = 318 /* UNARY_MINUS */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Token kinds. */ #define YYEMPTY -2 #define _END_OF_FILE_ 0 #define YYerror 256 #define YYUNDEF 257 #define _END_OF_INCLUDED_FILE_ 258 #define _DOT_DOT_ 259 #define _RULE_ 260 #define _PRIVATE_ 261 #define _GLOBAL_ 262 #define _META_ 263 #define _STRINGS_ 264 #define _CONDITION_ 265 #define _IDENTIFIER_ 266 #define _STRING_IDENTIFIER_ 267 #define _STRING_COUNT_ 268 #define _STRING_OFFSET_ 269 #define _STRING_LENGTH_ 270 #define _STRING_IDENTIFIER_WITH_WILDCARD_ 271 #define _NUMBER_ 272 #define _DOUBLE_ 273 #define _INTEGER_FUNCTION_ 274 #define _TEXT_STRING_ 275 #define _HEX_STRING_ 276 #define _REGEXP_ 277 #define _ASCII_ 278 #define _WIDE_ 279 #define _XOR_ 280 #define _BASE64_ 281 #define _BASE64_WIDE_ 282 #define _NOCASE_ 283 #define _FULLWORD_ 284 #define _AT_ 285 #define _FILESIZE_ 286 #define _ENTRYPOINT_ 287 #define _ALL_ 288 #define _ANY_ 289 #define _NONE_ 290 #define _IN_ 291 #define _OF_ 292 #define _FOR_ 293 #define _THEM_ 294 #define _MATCHES_ 295 #define _CONTAINS_ 296 #define _STARTSWITH_ 297 #define _ENDSWITH_ 298 #define _ICONTAINS_ 299 #define _ISTARTSWITH_ 300 #define _IENDSWITH_ 301 #define _IEQUALS_ 302 #define _IMPORT_ 303 #define _TRUE_ 304 #define _FALSE_ 305 #define _OR_ 306 #define _AND_ 307 #define _NOT_ 308 #define _DEFINED_ 309 #define _EQ_ 310 #define _NEQ_ 311 #define _LT_ 312 #define _LE_ 313 #define _GT_ 314 #define _GE_ 315 #define _SHIFT_LEFT_ 316 #define _SHIFT_RIGHT_ 317 #define UNARY_MINUS 318 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 343 "libyara/grammar.y" YR_EXPRESSION expression; SIZED_STRING* sized_string; char* c_string; int64_t integer; double double_; YR_MODIFIER modifier; YR_ENUMERATION enumeration; YR_ARENA_REF tag; YR_ARENA_REF rule; YR_ARENA_REF meta; YR_ARENA_REF string; #line 208 "libyara/grammar.h" }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif int yara_yyparse (void *yyscanner, YR_COMPILER* compiler); #endif /* !YY_YARA_YY_LIBYARA_GRAMMAR_H_INCLUDED */ yara-4.5.3/libyara/grammar.y000066400000000000000000002572321501365277300157460ustar00rootroot00000000000000/* Copyright (c) 2007-2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // clang-format off %{ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(_MSC_VER) #define llabs _abs64 #endif #define YYERROR_VERBOSE #define YYMALLOC yr_malloc #define YYFREE yr_free #define FOR_EXPRESSION_ALL 1 #define FOR_EXPRESSION_ANY 2 #define FOR_EXPRESSION_NONE 3 #define FOR_ITERATION_ITERATOR 1 #define FOR_ITERATION_STRING_SET 2 // fail_with_error() is used in parser actions for aborting the parsing with // an error. If the error is recoverable (like syntax errors), the parser will // report the error and continue parsing the next rule. If the error is a // fatal, non-recoverable error, the parser will be completely aborted. #define fail_with_error(e) \ { \ compiler->last_error = e; \ yyerror(yyscanner, compiler, NULL); \ switch (e) \ { \ case ERROR_INSUFFICIENT_MEMORY: \ YYABORT; \ default: \ YYERROR; \ } \ } // fail_if_error() is used in parser actions for aborting the parsing if an // error has occurred. See fail_with_error for details. #define fail_if_error(e) \ if (e != ERROR_SUCCESS && e != ERROR_UNKNOWN_ESCAPE_SEQUENCE) \ { \ fail_with_error(e); \ } // check_type(expression, EXPRESSION_TYPE_INTEGER | EXPRESSION_TYPE_FLOAT) is // used to ensure that the type of "expression" is either integer or float, // the cleanup statements are executed if the condition is not met. #define check_type_with_cleanup(expression, expected_type, op, cleanup) \ if (((expression.type) & (expected_type)) == 0) \ { \ switch(expression.type) \ { \ case EXPRESSION_TYPE_INTEGER: \ yr_compiler_set_error_extra_info( \ compiler, "wrong type \"integer\" for " op " operator"); \ break; \ case EXPRESSION_TYPE_FLOAT: \ yr_compiler_set_error_extra_info( \ compiler, "wrong type \"float\" for " op " operator"); \ break; \ case EXPRESSION_TYPE_STRING: \ yr_compiler_set_error_extra_info( \ compiler, "wrong type \"string\" for " op " operator"); \ break; \ case EXPRESSION_TYPE_BOOLEAN: \ yr_compiler_set_error_extra_info( \ compiler, "wrong type \"boolean\" for " op " operator"); \ break; \ } \ cleanup; \ compiler->last_error = ERROR_WRONG_TYPE; \ yyerror(yyscanner, compiler, NULL); \ YYERROR; \ } // check_type(expression, EXPRESSION_TYPE_INTEGER | EXPRESSION_TYPE_FLOAT) is // used to ensure that the type of "expression" is either integer or float. #define check_type(expression, expected_type, op) \ check_type_with_cleanup(expression, expected_type, op, ) #define loop_vars_cleanup(loop_index) \ { \ YR_LOOP_CONTEXT* loop_ctx = &compiler->loop[loop_index]; \ for (int i = 0; i < loop_ctx->vars_count; i++) \ { \ yr_free((void*) loop_ctx->vars[i].identifier.ptr); \ loop_ctx->vars[i].identifier.ptr = NULL; \ loop_ctx->vars[i].identifier.ref = YR_ARENA_NULL_REF; \ } \ loop_ctx->vars_count = 0; \ } \ // Given a YR_EXPRESSION returns its identifier. It returns identifier.ptr if // not NULL and relies on identifier.ref if otherwise. #define expression_identifier(expr) \ ((expr).identifier.ptr != NULL ? \ (expr).identifier.ptr : \ (const char*) yr_arena_ref_to_ptr(compiler->arena, &(expr).identifier.ref)) #define DEFAULT_BASE64_ALPHABET \ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" %} %expect 1 // expect 1 shift/reduce conflicts // Uncomment this line to print parsing information that can be useful to // debug YARA's grammar. // %debug %name-prefix "yara_yy" %pure-parser %parse-param {void *yyscanner} %parse-param {YR_COMPILER* compiler} %lex-param {yyscan_t yyscanner} %lex-param {YR_COMPILER* compiler} // The parser produces more detailed syntax errors. Accepted values are // "simple", "verbose", "detailed" and "custom". Introduced in Bison 3.0 // with support for "simple" and "verbose". Values "custom" and "detailed" // were introduced in Bison 3.6. See: // https://www.gnu.org/software/bison/manual/html_node/_0025define-Summary.html %define parse.error verbose // Token that marks the end of the original file. %token _END_OF_FILE_ 0 "end of file" // Token that marks the end of included files, we can't use _END_OF_FILE_ // because bison stops parsing when it sees _END_OF_FILE_, we want to be // be able to identify the point where an included file ends, but continuing // parsing any content that follows. %token _END_OF_INCLUDED_FILE_ "end of included file" %token _DOT_DOT_ ".." %token _RULE_ "" %token _PRIVATE_ "" %token _GLOBAL_ "" %token _META_ "" %token _STRINGS_ "" %token _CONDITION_ "" %token _IDENTIFIER_ "identifier" %token _STRING_IDENTIFIER_ "string identifier" %token _STRING_COUNT_ "string count" %token _STRING_OFFSET_ "string offset" %token _STRING_LENGTH_ "string length" %token _STRING_IDENTIFIER_WITH_WILDCARD_ "string identifier with wildcard" %token _NUMBER_ "integer number" %token _DOUBLE_ "floating point number" %token _INTEGER_FUNCTION_ "integer function" %token _TEXT_STRING_ "text string" %token _HEX_STRING_ "hex string" %token _REGEXP_ "regular expression" %token _ASCII_ "" %token _WIDE_ "" %token _XOR_ "" %token _BASE64_ "" %token _BASE64_WIDE_ "" %token _NOCASE_ "" %token _FULLWORD_ "" %token _AT_ "" %token _FILESIZE_ "" %token _ENTRYPOINT_ "" %token _ALL_ "" %token _ANY_ "" %token _NONE_ "" %token _IN_ "" %token _OF_ "" %token _FOR_ "" %token _THEM_ "" %token _MATCHES_ "" %token _CONTAINS_ "" %token _STARTSWITH_ "" %token _ENDSWITH_ "" %token _ICONTAINS_ "" %token _ISTARTSWITH_ "" %token _IENDSWITH_ "" %token _IEQUALS_ "" %token _IMPORT_ "" %token _TRUE_ "" %token _FALSE_ "" %token _OR_ "" %token _AND_ "" %token _NOT_ "" %token _DEFINED_ "" %token _EQ_ "==" %token _NEQ_ "!=" %token _LT_ "<" %token _LE_ "<=" %token _GT_ ">" %token _GE_ ">=" %token _SHIFT_LEFT_ "<<" %token _SHIFT_RIGHT_ ">>" // Operator precedence and associativity. Higher precedence operators are lower // in the list. Operators that appear in the same line have the same precedence. %left _OR_ %left _AND_ %right _NOT_ _DEFINED_ %left _EQ_ _NEQ_ _CONTAINS_ _ICONTAINS_ _STARTSWITH_ _ENDSWITH_ _ISTARTSWITH_ _IENDSWITH_ _IEQUALS_ _MATCHES_ %left _LT_ _LE_ _GT_ _GE_ %left '|' %left '^' %left '&' %left _SHIFT_LEFT_ _SHIFT_RIGHT_ %left '+' '-' %left '*' '\\' '%' %right '~' UNARY_MINUS %type rule %type strings %type string_declaration %type string_declarations %type meta %type meta_declaration %type meta_declarations %type tags %type tag_list %type string_modifier %type string_modifiers %type regexp_modifier %type regexp_modifiers %type hex_modifier %type hex_modifiers %type set %type enumeration %type rule_modifier %type rule_modifiers %type string_enumeration %type string_enumeration_item %type string_set %type for_iteration %type rule_enumeration %type rule_enumeration_item %type rule_set %type primary_expression %type boolean_expression %type expression %type identifier %type regexp %type for_expression %type for_quantifier %type condition %type arguments %type arguments_list %destructor { yr_free($$); $$ = NULL; } _IDENTIFIER_ %destructor { yr_free($$); $$ = NULL; } _STRING_COUNT_ %destructor { yr_free($$); $$ = NULL; } _STRING_OFFSET_ %destructor { yr_free($$); $$ = NULL; } _STRING_LENGTH_ %destructor { yr_free($$); $$ = NULL; } _STRING_IDENTIFIER_ %destructor { yr_free($$); $$ = NULL; } _STRING_IDENTIFIER_WITH_WILDCARD_ %destructor { yr_free($$); $$ = NULL; } _TEXT_STRING_ %destructor { yr_free($$); $$ = NULL; } _HEX_STRING_ %destructor { yr_free($$); $$ = NULL; } _REGEXP_ %destructor { yr_free($$); $$ = NULL; } arguments %destructor { yr_free($$); $$ = NULL; } arguments_list %destructor { if ($$.alphabet != NULL) { yr_free($$.alphabet); $$.alphabet = NULL; } } string_modifier %destructor { if ($$.alphabet != NULL) { yr_free($$.alphabet); $$.alphabet = NULL; } } string_modifiers %union { YR_EXPRESSION expression; SIZED_STRING* sized_string; char* c_string; int64_t integer; double double_; YR_MODIFIER modifier; YR_ENUMERATION enumeration; YR_ARENA_REF tag; YR_ARENA_REF rule; YR_ARENA_REF meta; YR_ARENA_REF string; } %% rules : /* empty */ | rules rule | rules import | rules error rule /* on error skip until next rule..*/ | rules error import /* .. or import statement */ | rules error "include" /* .. or include statement */ | rules _END_OF_INCLUDED_FILE_ { _yr_compiler_pop_file_name(compiler); } | rules error _END_OF_INCLUDED_FILE_ { _yr_compiler_pop_file_name(compiler); } ; import : _IMPORT_ _TEXT_STRING_ { int result = yr_parser_reduce_import(yyscanner, $2); yr_free($2); fail_if_error(result); } ; rule : rule_modifiers _RULE_ _IDENTIFIER_ { fail_if_error(yr_parser_reduce_rule_declaration_phase_1( yyscanner, (int32_t) $1, $3, &$$)); } tags '{' meta strings { YR_RULE* rule = (YR_RULE*) yr_arena_ref_to_ptr( compiler->arena, &$4); rule->tags = (char*) yr_arena_ref_to_ptr( compiler->arena, &$5); rule->metas = (YR_META*) yr_arena_ref_to_ptr( compiler->arena, &$7); rule->strings = (YR_STRING*) yr_arena_ref_to_ptr( compiler->arena, &$8); } condition '}' { YR_RULE* rule = (YR_RULE*) yr_arena_ref_to_ptr( compiler->arena, &$4); rule->required_strings = $10.required_strings.count; int result = yr_parser_reduce_rule_declaration_phase_2( yyscanner, &$4); // rule created in phase 1 yr_free($3); fail_if_error(result); } ; meta : /* empty */ { $$ = YR_ARENA_NULL_REF; } | _META_ ':' meta_declarations { YR_META* meta = yr_arena_get_ptr( compiler->arena, YR_METAS_TABLE, (compiler->current_meta_idx - 1) * sizeof(YR_META)); meta->flags |= META_FLAGS_LAST_IN_RULE; $$ = $3; } ; strings : /* empty */ { $$ = YR_ARENA_NULL_REF; } | _STRINGS_ ':' string_declarations { YR_STRING* string = (YR_STRING*) yr_arena_get_ptr( compiler->arena, YR_STRINGS_TABLE, (compiler->current_string_idx - 1) * sizeof(YR_STRING)); string->flags |= STRING_FLAGS_LAST_IN_RULE; $$ = $3; } ; condition : _CONDITION_ ':' boolean_expression { $$ = $3; } ; rule_modifiers : /* empty */ { $$ = 0; } | rule_modifiers rule_modifier { $$ = $1 | $2; } ; rule_modifier : _PRIVATE_ { $$ = RULE_FLAGS_PRIVATE; } | _GLOBAL_ { $$ = RULE_FLAGS_GLOBAL; } ; tags : /* empty */ { $$ = YR_ARENA_NULL_REF; } | ':' tag_list { // Tags list is represented in the arena as a sequence // of null-terminated strings, the sequence ends with an // additional null character. Here we write the ending null //character. Example: tag1\0tag2\0tag3\0\0 fail_if_error(yr_arena_write_string( yyget_extra(yyscanner)->arena, YR_SZ_POOL, "", NULL)); $$ = $2; } ; tag_list : _IDENTIFIER_ { int result = yr_arena_write_string( yyget_extra(yyscanner)->arena, YR_SZ_POOL, $1, &$$); yr_free($1); fail_if_error(result); } | tag_list _IDENTIFIER_ { YR_ARENA_REF ref; // Write the new tag identifier. int result = yr_arena_write_string( yyget_extra(yyscanner)->arena, YR_SZ_POOL, $2, &ref); yr_free($2); fail_if_error(result); // Get the address for the tag identifier just written. char* new_tag = (char*) yr_arena_ref_to_ptr( compiler->arena, &ref); // Take the address of first tag's identifier in the list. char* tag = (char*) yr_arena_ref_to_ptr( compiler->arena, &$$); // Search for duplicated tags. Tags are written one after // the other, with zeroes in between (i.e: tag1/0tag2/0tag3) // that's why can use tag < new_tag as the condition for the // loop. while (tag < new_tag) { if (strcmp(tag, new_tag) == 0) { yr_compiler_set_error_extra_info(compiler, tag); fail_with_error(ERROR_DUPLICATED_TAG_IDENTIFIER); } tag += strlen(tag) + 1; } $$ = $1; } ; meta_declarations : meta_declaration { $$ = $1; } | meta_declarations meta_declaration { $$ = $1; } ; meta_declaration : _IDENTIFIER_ '=' _TEXT_STRING_ { SIZED_STRING* sized_string = $3; int result = yr_parser_reduce_meta_declaration( yyscanner, META_TYPE_STRING, $1, sized_string->c_string, 0, &$$); yr_free($1); yr_free($3); fail_if_error(result); } | _IDENTIFIER_ '=' _NUMBER_ { int result = yr_parser_reduce_meta_declaration( yyscanner, META_TYPE_INTEGER, $1, NULL, $3, &$$); yr_free($1); fail_if_error(result); } | _IDENTIFIER_ '=' '-' _NUMBER_ { int result = yr_parser_reduce_meta_declaration( yyscanner, META_TYPE_INTEGER, $1, NULL, -$4, &$$); yr_free($1); fail_if_error(result); } | _IDENTIFIER_ '=' _TRUE_ { int result = yr_parser_reduce_meta_declaration( yyscanner, META_TYPE_BOOLEAN, $1, NULL, true, &$$); yr_free($1); fail_if_error(result); } | _IDENTIFIER_ '=' _FALSE_ { int result = yr_parser_reduce_meta_declaration( yyscanner, META_TYPE_BOOLEAN, $1, NULL, false, &$$); yr_free($1); fail_if_error(result); } ; string_declarations : string_declaration { $$ = $1; } | string_declarations string_declaration { $$ = $1; } ; string_declaration : _STRING_IDENTIFIER_ '=' { compiler->current_line = yyget_lineno(yyscanner); } _TEXT_STRING_ string_modifiers { int result = yr_parser_reduce_string_declaration( yyscanner, $5, $1, $4, &$$); yr_free($1); yr_free($4); yr_free($5.alphabet); fail_if_error(result); compiler->current_line = 0; } | _STRING_IDENTIFIER_ '=' { compiler->current_line = yyget_lineno(yyscanner); } _REGEXP_ regexp_modifiers { int result; $5.flags |= STRING_FLAGS_REGEXP; result = yr_parser_reduce_string_declaration( yyscanner, $5, $1, $4, &$$); yr_free($1); yr_free($4); fail_if_error(result); compiler->current_line = 0; } | _STRING_IDENTIFIER_ '=' { compiler->current_line = yyget_lineno(yyscanner); } _HEX_STRING_ hex_modifiers { int result; $5.flags |= STRING_FLAGS_HEXADECIMAL; result = yr_parser_reduce_string_declaration( yyscanner, $5, $1, $4, &$$); yr_free($1); yr_free($4); fail_if_error(result); compiler->current_line = 0; } ; string_modifiers : /* empty */ { $$.flags = 0; $$.xor_min = 0; $$.xor_max = 0; $$.alphabet = NULL; } | string_modifiers string_modifier { $$ = $1; // Only set the xor minimum and maximum if we are dealing with the // xor modifier. If we don't check for this then we can end up with // "xor wide" resulting in whatever is on the stack for "wide" // overwriting the values for xor. if ($2.flags & STRING_FLAGS_XOR) { $$.xor_min = $2.xor_min; $$.xor_max = $2.xor_max; } // Only set the base64 alphabet if we are dealing with the base64 // modifier. If we don't check for this then we can end up with // "base64 ascii" resulting in whatever is on the stack for "ascii" // overwriting the values for base64. if (($2.flags & STRING_FLAGS_BASE64) || ($2.flags & STRING_FLAGS_BASE64_WIDE)) { if ($$.alphabet != NULL) { if (ss_compare($$.alphabet, $2.alphabet) != 0) { yr_compiler_set_error_extra_info( compiler, "can not specify multiple alphabets"); yr_free($2.alphabet); yr_free($$.alphabet); fail_with_error(ERROR_INVALID_MODIFIER); } else { yr_free($2.alphabet); } } else { $$.alphabet = $2.alphabet; } } if ($$.flags & $2.flags) { if ($$.alphabet != NULL) yr_free($$.alphabet); fail_with_error(ERROR_DUPLICATED_MODIFIER); } else { $$.flags = $$.flags | $2.flags; } } ; string_modifier : _WIDE_ { $$.flags = STRING_FLAGS_WIDE; } | _ASCII_ { $$.flags = STRING_FLAGS_ASCII; } | _NOCASE_ { $$.flags = STRING_FLAGS_NO_CASE; } | _FULLWORD_ { $$.flags = STRING_FLAGS_FULL_WORD; } | _PRIVATE_ { $$.flags = STRING_FLAGS_PRIVATE; } | _XOR_ { $$.flags = STRING_FLAGS_XOR; $$.xor_min = 0; $$.xor_max = 255; } | _XOR_ '(' _NUMBER_ ')' { int result = ERROR_SUCCESS; if ($3 < 0 || $3 > 255) { yr_compiler_set_error_extra_info(compiler, "invalid xor range"); result = ERROR_INVALID_MODIFIER; } fail_if_error(result); $$.flags = STRING_FLAGS_XOR; $$.xor_min = (uint8_t) $3; $$.xor_max = (uint8_t) $3; } /* * Would love to use range here for consistency in the language but that * uses a primary expression which pushes a value on the VM stack we don't * account for. */ | _XOR_ '(' _NUMBER_ '-' _NUMBER_ ')' { int result = ERROR_SUCCESS; if ($3 < 0) { yr_compiler_set_error_extra_info( compiler, "lower bound for xor range exceeded (min: 0)"); result = ERROR_INVALID_MODIFIER; } if ($5 > 255) { yr_compiler_set_error_extra_info( compiler, "upper bound for xor range exceeded (max: 255)"); result = ERROR_INVALID_MODIFIER; } if ($3 > $5) { yr_compiler_set_error_extra_info( compiler, "xor lower bound exceeds upper bound"); result = ERROR_INVALID_MODIFIER; } fail_if_error(result); $$.flags = STRING_FLAGS_XOR; $$.xor_min = (uint8_t) $3; $$.xor_max = (uint8_t) $5; } | _BASE64_ { $$.flags = STRING_FLAGS_BASE64; $$.alphabet = ss_new(DEFAULT_BASE64_ALPHABET); } | _BASE64_ '(' _TEXT_STRING_ ')' { int result = ERROR_SUCCESS; if ($3->length != 64) { yr_free($3); yr_compiler_set_error_extra_info( compiler, "length of base64 alphabet must be 64"); result = ERROR_INVALID_MODIFIER; } fail_if_error(result); $$.flags = STRING_FLAGS_BASE64; $$.alphabet = $3; } | _BASE64_WIDE_ { $$.flags = STRING_FLAGS_BASE64_WIDE; $$.alphabet = ss_new(DEFAULT_BASE64_ALPHABET); } | _BASE64_WIDE_ '(' _TEXT_STRING_ ')' { int result = ERROR_SUCCESS; if ($3->length != 64) { yr_free($3); yr_compiler_set_error_extra_info( compiler, "length of base64 alphabet must be 64"); result = ERROR_INVALID_MODIFIER; } fail_if_error(result); $$.flags = STRING_FLAGS_BASE64_WIDE; $$.alphabet = $3; } ; regexp_modifiers : /* empty */ { $$.flags = 0; } | regexp_modifiers regexp_modifier { if ($1.flags & $2.flags) { fail_with_error(ERROR_DUPLICATED_MODIFIER); } else { $$.flags = $1.flags | $2.flags; } } ; regexp_modifier : _WIDE_ { $$.flags = STRING_FLAGS_WIDE; } | _ASCII_ { $$.flags = STRING_FLAGS_ASCII; } | _NOCASE_ { $$.flags = STRING_FLAGS_NO_CASE; } | _FULLWORD_ { $$.flags = STRING_FLAGS_FULL_WORD; } | _PRIVATE_ { $$.flags = STRING_FLAGS_PRIVATE; } ; hex_modifiers : /* empty */ { $$.flags = 0; } | hex_modifiers hex_modifier { if ($1.flags & $2.flags) { fail_with_error(ERROR_DUPLICATED_MODIFIER); } else { $$.flags = $1.flags | $2.flags; } } ; hex_modifier : _PRIVATE_ { $$.flags = STRING_FLAGS_PRIVATE; } ; identifier : _IDENTIFIER_ { YR_EXPRESSION expr; int result = ERROR_SUCCESS; int var_index = yr_parser_lookup_loop_variable(yyscanner, $1, &expr); if (var_index >= 0) { // The identifier corresponds to a loop variable. result = yr_parser_emit_with_arg( yyscanner, OP_PUSH_M, var_index, NULL, NULL); // The expression associated to this identifier is the same one // associated to the loop variable. $$ = expr; } else { // Search for identifier within the global namespace, where the // externals variables reside. YR_OBJECT* object = (YR_OBJECT*) yr_hash_table_lookup( compiler->objects_table, $1, NULL); YR_NAMESPACE* ns = (YR_NAMESPACE*) yr_arena_get_ptr( compiler->arena, YR_NAMESPACES_TABLE, compiler->current_namespace_idx * sizeof(struct YR_NAMESPACE)); if (object == NULL) { // If not found, search within the current namespace. object = (YR_OBJECT*) yr_hash_table_lookup( compiler->objects_table, $1, ns->name); } if (object != NULL) { YR_ARENA_REF ref; result = _yr_compiler_store_string( compiler, $1, &ref); if (result == ERROR_SUCCESS) result = yr_parser_emit_with_arg_reloc( yyscanner, OP_OBJ_LOAD, yr_arena_ref_to_ptr(compiler->arena, &ref), NULL, NULL); $$.type = EXPRESSION_TYPE_OBJECT; $$.value.object = object; $$.identifier.ptr = NULL; $$.identifier.ref = ref; } else { uint32_t rule_idx = yr_hash_table_lookup_uint32( compiler->rules_table, $1, ns->name); if (rule_idx != UINT32_MAX) { result = yr_parser_emit_with_arg( yyscanner, OP_PUSH_RULE, rule_idx, NULL, NULL); YR_RULE* rule = _yr_compiler_get_rule_by_idx(compiler, rule_idx); yr_arena_ptr_to_ref(compiler->arena, rule->identifier, &$$.identifier.ref); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.value.integer = YR_UNDEFINED; $$.identifier.ptr = NULL; $$.required_strings.count = 0; } else { yr_compiler_set_error_extra_info(compiler, $1); result = ERROR_UNDEFINED_IDENTIFIER; } } } yr_free($1); fail_if_error(result); } | identifier '.' _IDENTIFIER_ { int result = ERROR_SUCCESS; YR_OBJECT* field = NULL; if ($1.type == EXPRESSION_TYPE_OBJECT && $1.value.object->type == OBJECT_TYPE_STRUCTURE) { field = yr_object_lookup_field($1.value.object, $3); if (field != NULL) { YR_ARENA_REF ref; result = _yr_compiler_store_string( compiler, $3, &ref); if (result == ERROR_SUCCESS) result = yr_parser_emit_with_arg_reloc( yyscanner, OP_OBJ_FIELD, yr_arena_ref_to_ptr(compiler->arena, &ref), NULL, NULL); $$.type = EXPRESSION_TYPE_OBJECT; $$.value.object = field; $$.identifier.ref = ref; $$.identifier.ptr = NULL; } else { yr_compiler_set_error_extra_info(compiler, $3); result = ERROR_INVALID_FIELD_NAME; } } else { yr_compiler_set_error_extra_info( compiler, expression_identifier($1)); result = ERROR_NOT_A_STRUCTURE; } yr_free($3); fail_if_error(result); } | identifier '[' primary_expression ']' { int result = ERROR_SUCCESS; YR_OBJECT_ARRAY* array; YR_OBJECT_DICTIONARY* dict; if ($1.type == EXPRESSION_TYPE_OBJECT && $1.value.object->type == OBJECT_TYPE_ARRAY) { if ($3.type != EXPRESSION_TYPE_INTEGER) { yr_compiler_set_error_extra_info( compiler, "array indexes must be of integer type"); result = ERROR_WRONG_TYPE; } fail_if_error(result); result = yr_parser_emit( yyscanner, OP_INDEX_ARRAY, NULL); array = object_as_array($1.value.object); $$.type = EXPRESSION_TYPE_OBJECT; $$.value.object = array->prototype_item; $$.identifier.ptr = array->identifier; $$.identifier.ref = YR_ARENA_NULL_REF; } else if ($1.type == EXPRESSION_TYPE_OBJECT && $1.value.object->type == OBJECT_TYPE_DICTIONARY) { if ($3.type != EXPRESSION_TYPE_STRING) { yr_compiler_set_error_extra_info( compiler, "dictionary keys must be of string type"); result = ERROR_WRONG_TYPE; } fail_if_error(result); result = yr_parser_emit( yyscanner, OP_LOOKUP_DICT, NULL); dict = object_as_dictionary($1.value.object); $$.type = EXPRESSION_TYPE_OBJECT; $$.value.object = dict->prototype_item; $$.identifier.ptr = dict->identifier; $$.identifier.ref = YR_ARENA_NULL_REF; } else { yr_compiler_set_error_extra_info( compiler, expression_identifier($1)); result = ERROR_NOT_INDEXABLE; } fail_if_error(result); } | identifier '(' arguments ')' { YR_ARENA_REF ref = YR_ARENA_NULL_REF; int result = ERROR_SUCCESS; if ($1.type == EXPRESSION_TYPE_OBJECT && $1.value.object->type == OBJECT_TYPE_FUNCTION) { YR_OBJECT_FUNCTION* function = object_as_function($1.value.object); result = yr_parser_check_types(compiler, function, $3); if (result == ERROR_SUCCESS) result = _yr_compiler_store_string( compiler, $3, &ref); if (result == ERROR_SUCCESS) result = yr_parser_emit_with_arg_reloc( yyscanner, OP_CALL, yr_arena_ref_to_ptr(compiler->arena, &ref), NULL, NULL); $$.type = EXPRESSION_TYPE_OBJECT; $$.value.object = function->return_obj; $$.identifier.ref = ref; $$.identifier.ptr = NULL; } else { yr_compiler_set_error_extra_info( compiler, expression_identifier($1)); result = ERROR_NOT_A_FUNCTION; } yr_free($3); fail_if_error(result); } ; arguments : /* empty */ { $$ = yr_strdup(""); } | arguments_list { $$ = $1; } arguments_list : expression { $$ = (char*) yr_malloc(YR_MAX_FUNCTION_ARGS + 1); if ($$ == NULL) fail_with_error(ERROR_INSUFFICIENT_MEMORY); switch($1.type) { case EXPRESSION_TYPE_INTEGER: strlcpy($$, "i", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_FLOAT: strlcpy($$, "f", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_BOOLEAN: strlcpy($$, "b", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_STRING: strlcpy($$, "s", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_REGEXP: strlcpy($$, "r", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_UNKNOWN: yr_free($$); yr_compiler_set_error_extra_info( compiler, "unknown type for argument 1 in function call"); fail_with_error(ERROR_WRONG_TYPE); break; default: // An unknown expression type is OK iff an error ocurred. assert(compiler->last_error != ERROR_SUCCESS); } } | arguments_list ',' expression { int result = ERROR_SUCCESS; if (strlen($1) == YR_MAX_FUNCTION_ARGS) { result = ERROR_TOO_MANY_ARGUMENTS; } else { switch($3.type) { case EXPRESSION_TYPE_INTEGER: strlcat($1, "i", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_FLOAT: strlcat($1, "f", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_BOOLEAN: strlcat($1, "b", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_STRING: strlcat($1, "s", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_REGEXP: strlcat($1, "r", YR_MAX_FUNCTION_ARGS); break; case EXPRESSION_TYPE_UNKNOWN: result = ERROR_WRONG_TYPE; yr_compiler_set_error_extra_info_fmt( compiler, "unknown type for argument %zu in function call", // As we add one character per argument, the length of $1 is // the number of arguments parsed so far, and the argument // represented by is length of $1 plus one. strlen($1) + 1); break; default: // An unknown expression type is OK iff an error ocurred. assert(compiler->last_error != ERROR_SUCCESS); } } if (result != ERROR_SUCCESS) yr_free($1); fail_if_error(result); $$ = $1; } ; regexp : _REGEXP_ { YR_ARENA_REF re_ref; RE_ERROR error; int result = ERROR_SUCCESS; int re_flags = 0; int parser_flags = RE_PARSER_FLAG_NONE; if ($1->flags & SIZED_STRING_FLAGS_NO_CASE) re_flags |= RE_FLAGS_NO_CASE; if ($1->flags & SIZED_STRING_FLAGS_DOT_ALL) re_flags |= RE_FLAGS_DOT_ALL; if (compiler->strict_escape) parser_flags |= RE_PARSER_FLAG_ENABLE_STRICT_ESCAPE_SEQUENCES; result = yr_re_compile( $1->c_string, re_flags, parser_flags, compiler->arena, &re_ref, &error); yr_free($1); if (result == ERROR_INVALID_REGULAR_EXPRESSION) yr_compiler_set_error_extra_info(compiler, error.message); if (result == ERROR_SUCCESS || result == ERROR_UNKNOWN_ESCAPE_SEQUENCE) { if (result == ERROR_UNKNOWN_ESCAPE_SEQUENCE) { yywarning( yyscanner, "unknown escape sequence"); } result = yr_parser_emit_with_arg_reloc( yyscanner, OP_PUSH, yr_arena_ref_to_ptr(compiler->arena, &re_ref), NULL, NULL); } fail_if_error(result); $$.type = EXPRESSION_TYPE_REGEXP; } ; boolean_expression : expression { if ($1.type == EXPRESSION_TYPE_STRING) { if (!YR_ARENA_IS_NULL_REF($1.value.sized_string_ref)) { SIZED_STRING* sized_string = yr_arena_ref_to_ptr( compiler->arena, &$1.value.sized_string_ref); yywarning(yyscanner, "using literal string \"%s\" in a boolean operation.", sized_string->c_string); } fail_if_error(yr_parser_emit( yyscanner, OP_STR_TO_BOOL, NULL)); } if ($1.type != EXPRESSION_TYPE_BOOLEAN) { $$.required_strings.count = 0; } else { $$.required_strings.count = $1.required_strings.count; } $$.type = EXPRESSION_TYPE_BOOLEAN; } ; expression : _TRUE_ { fail_if_error(yr_parser_emit_push_const(yyscanner, 1)); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | _FALSE_ { fail_if_error(yr_parser_emit_push_const(yyscanner, 0)); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | primary_expression _MATCHES_ regexp { check_type($1, EXPRESSION_TYPE_STRING, "matches"); check_type($3, EXPRESSION_TYPE_REGEXP, "matches"); fail_if_error(yr_parser_emit( yyscanner, OP_MATCHES, NULL)); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | primary_expression _CONTAINS_ primary_expression { check_type($1, EXPRESSION_TYPE_STRING, "contains"); check_type($3, EXPRESSION_TYPE_STRING, "contains"); fail_if_error(yr_parser_emit( yyscanner, OP_CONTAINS, NULL)); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | primary_expression _ICONTAINS_ primary_expression { check_type($1, EXPRESSION_TYPE_STRING, "icontains"); check_type($3, EXPRESSION_TYPE_STRING, "icontains"); fail_if_error(yr_parser_emit( yyscanner, OP_ICONTAINS, NULL)); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | primary_expression _STARTSWITH_ primary_expression { check_type($1, EXPRESSION_TYPE_STRING, "startswith"); check_type($3, EXPRESSION_TYPE_STRING, "startswith"); fail_if_error(yr_parser_emit( yyscanner, OP_STARTSWITH, NULL)); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | primary_expression _ISTARTSWITH_ primary_expression { check_type($1, EXPRESSION_TYPE_STRING, "istartswith"); check_type($3, EXPRESSION_TYPE_STRING, "istartswith"); fail_if_error(yr_parser_emit( yyscanner, OP_ISTARTSWITH, NULL)); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | primary_expression _ENDSWITH_ primary_expression { check_type($1, EXPRESSION_TYPE_STRING, "endswith"); check_type($3, EXPRESSION_TYPE_STRING, "endswith"); fail_if_error(yr_parser_emit( yyscanner, OP_ENDSWITH, NULL)); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | primary_expression _IENDSWITH_ primary_expression { check_type($1, EXPRESSION_TYPE_STRING, "iendswith"); check_type($3, EXPRESSION_TYPE_STRING, "iendswith"); fail_if_error(yr_parser_emit( yyscanner, OP_IENDSWITH, NULL)); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | primary_expression _IEQUALS_ primary_expression { check_type($1, EXPRESSION_TYPE_STRING, "iequals"); check_type($3, EXPRESSION_TYPE_STRING, "iequals"); fail_if_error(yr_parser_emit( yyscanner, OP_IEQUALS, NULL)); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | _STRING_IDENTIFIER_ { int result = yr_parser_reduce_string_identifier( yyscanner, $1, OP_FOUND, YR_UNDEFINED); yr_free($1); fail_if_error(result); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 1; } | _STRING_IDENTIFIER_ _AT_ primary_expression { int result; check_type_with_cleanup($3, EXPRESSION_TYPE_INTEGER, "at", yr_free($1)); result = yr_parser_reduce_string_identifier( yyscanner, $1, OP_FOUND_AT, $3.value.integer); yr_free($1); fail_if_error(result); $$.required_strings.count = 1; $$.type = EXPRESSION_TYPE_BOOLEAN; } | _STRING_IDENTIFIER_ _IN_ range { int result = yr_parser_reduce_string_identifier( yyscanner, $1, OP_FOUND_IN, YR_UNDEFINED); yr_free($1); fail_if_error(result); $$.required_strings.count = 1; $$.type = EXPRESSION_TYPE_BOOLEAN; } | _FOR_ for_expression error { // Free all the loop variable identifiers, including the variables for // the current loop (represented by loop_index), and set loop_index to // -1. This is OK even if we have nested loops. If an error occurs while // parsing the inner loop, it will be propagated to the outer loop // anyways, so it's safe to do this cleanup while processing the error // for the inner loop. for (int i = 0; i <= compiler->loop_index; i++) { loop_vars_cleanup(i); } compiler->loop_index = -1; YYERROR; } | _FOR_ for_expression // // for in : () // // CLEAR_M 0 ; clear number of true results returned by // CLEAR_M 1 ; clear loop iteration counter // POP_M 2 ; takes the result of from the stack // ; and puts it in M[2], once M[0] reaches M[2] the whole // ; for expression is satisfied // ; the instructions generated by the depend // ; on the type of iterator, but they will initialize the // ; iterator and get it ready for the ITER_NEXT instruction. // repeat: // ITER_NEXT ; reads the iterator object from the stack but leaves it there, // ; puts next item in the sequence in the stack, and also a TRUE // ; or a FALSE value indicating whether or not there are more items // // POP_M 3 ; pops the next item from the stack and puts it in M[3], it // ; can be even more POPs depending on the type of the loop. // ; loops usually have just a single variable but loops over // ; dictionaries will have more POPs here. // // JTRUE_P epilog ; pops the boolean that tells if we already reached // ; the end of the iterator // ; here goes the code for the value of the // ; expressions ends up being at the top of the stack // // INCR_M 1 ; increments iteration counter // PUSH_M 0 ; push M[0] - number of true expressions // PUSH_M 2 ; push M[2] - of this loop // ITER_CONDITION ; reads the top 3 values from the stack which are // ; (in this order from the top) // ; 1. of this loop // ; 2. number of true expressions // ; 3. result of the body // ; and determines whether the loop should continue // ; according to the short-circuit evaluation. // ; leaves 2 values on the stack (in this order from the top) // ; 1. result of the body // ; 2. indicator whether the loop should continue or not // // ADD_M 0 ; if was true M[0] is incremented by one, // ; this consumes the 's result from the stack // // JTRUE_P repeat ; repeat the loop if ITER_CONDITION left true on the stack // // epilog: // POP ; remove the iterator object from the stack // // PUSH_M 1 ; push iteration counter // PUSH_M 0 ; pushes number of true results for // PUSH_M 2 ; pushes value of // // ITER_END ; final evaluation of the loop according to it's // ; iteration counter, number of true expressions // ; and value of // end: // { // var_frame is used for accessing local variables used in this loop. // All local variables are accessed using var_frame as a reference, // like var_frame + 0, var_frame + 1, etc. Here we initialize var_frame // with the correct value, which depends on the number of variables // defined by any outer loops. int var_frame; int result = ERROR_SUCCESS; if (compiler->loop_index + 1 == YR_MAX_LOOP_NESTING) result = ERROR_LOOP_NESTING_LIMIT_EXCEEDED; fail_if_error(result); compiler->loop_index++; // This loop uses internal variables besides the ones explicitly // defined by the user. compiler->loop[compiler->loop_index].vars_internal_count = \ YR_INTERNAL_LOOP_VARS; // Initialize the number of variables, this number will be incremented // as variable declaration are processed by for_variables. compiler->loop[compiler->loop_index].vars_count = 0; var_frame = _yr_compiler_get_var_frame(compiler); fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_CLEAR_M, var_frame + 0, NULL, NULL)); fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_CLEAR_M, var_frame + 1, NULL, NULL)); fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_POP_M, var_frame + 2, NULL, NULL)); } for_iteration ':' { YR_LOOP_CONTEXT* loop_ctx = &compiler->loop[compiler->loop_index]; YR_FIXUP* fixup; YR_ARENA_REF loop_start_ref; YR_ARENA_REF jmp_offset_ref; int var_frame = _yr_compiler_get_var_frame(compiler); fail_if_error(yr_parser_emit( yyscanner, OP_ITER_NEXT, &loop_start_ref)); // For each variable generate an instruction that pops the value from // the stack and store it into one memory slot starting at var_frame + // YR_INTERNAL_LOOP_VARS because the first YR_INTERNAL_LOOP_VARS slots // in the frame are for the internal variables. for (int i = 0; i < loop_ctx->vars_count; i++) { fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_POP_M, var_frame + YR_INTERNAL_LOOP_VARS + i, NULL, NULL)); } fail_if_error(yr_parser_emit_with_arg_int32( yyscanner, OP_JTRUE_P, 0, // still don't know the jump offset, use 0 for now. NULL, &jmp_offset_ref)); // We still don't know the jump's target, so we push a fixup entry // in the stack, so that the jump's offset can be set once we know it. fixup = (YR_FIXUP*) yr_malloc(sizeof(YR_FIXUP)); if (fixup == NULL) fail_with_error(ERROR_INSUFFICIENT_MEMORY); fixup->ref = jmp_offset_ref; fixup->next = compiler->fixup_stack_head; compiler->fixup_stack_head = fixup; loop_ctx->start_ref = loop_start_ref; } '(' boolean_expression ')' { int32_t jmp_offset; YR_FIXUP* fixup; YR_ARENA_REF pop_ref; int var_frame = _yr_compiler_get_var_frame(compiler); if ($4 == FOR_ITERATION_STRING_SET) { compiler->loop_for_of_var_index = -1; } fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_INCR_M, var_frame + 1, NULL, NULL)); fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_PUSH_M, var_frame + 0, NULL, NULL)); fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_PUSH_M, var_frame + 2, NULL, NULL)); fail_if_error(yr_parser_emit(yyscanner, OP_ITER_CONDITION, NULL)); fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_ADD_M, var_frame + 0, NULL, NULL)); jmp_offset = \ compiler->loop[compiler->loop_index].start_ref.offset - yr_arena_get_current_offset(compiler->arena, YR_CODE_SECTION); fail_if_error(yr_parser_emit_with_arg_int32( yyscanner, OP_JTRUE_P, jmp_offset, NULL, NULL)); fail_if_error(yr_parser_emit( yyscanner, OP_POP, &pop_ref)); // Pop from the stack the fixup entry containing the reference to // the jump offset that needs to be fixed. fixup = compiler->fixup_stack_head; compiler->fixup_stack_head = fixup->next; // The fixup entry has a reference to the jump offset that need // to be fixed, convert the address into a pointer. int32_t* jmp_offset_addr = (int32_t*) yr_arena_ref_to_ptr( compiler->arena, &fixup->ref); // The reference in the fixup entry points to the jump's offset // but the jump instruction is one byte before, that's why we add // one to the offset. jmp_offset = pop_ref.offset - fixup->ref.offset + 1; // Fix the jump's offset. memcpy(jmp_offset_addr, &jmp_offset, sizeof(jmp_offset)); yr_free(fixup); fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_PUSH_M, var_frame + 1, NULL, NULL)); fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_PUSH_M, var_frame + 0, NULL, NULL)); fail_if_error(yr_parser_emit_with_arg( yyscanner, OP_PUSH_M, var_frame + 2, NULL, NULL)); fail_if_error(yr_parser_emit( yyscanner, OP_ITER_END, NULL)); loop_vars_cleanup(compiler->loop_index); compiler->loop_index--; $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | for_expression _OF_ string_set { if ($1.type == EXPRESSION_TYPE_INTEGER && $1.value.integer > $3) { yywarning(yyscanner, "expression always false - requesting %" PRId64 " of %" PRId64 ".", $1.value.integer, $3); } if (($1.type == EXPRESSION_TYPE_INTEGER && $1.value.integer > 0) || ($1.type == EXPRESSION_TYPE_QUANTIFIER && ($1.value.integer == FOR_EXPRESSION_ALL || $1.value.integer == FOR_EXPRESSION_ANY))) { $$.required_strings.count = 1; } else { $$.required_strings.count = 0; } yr_parser_emit_with_arg(yyscanner, OP_OF, OF_STRING_SET, NULL, NULL); $$.type = EXPRESSION_TYPE_BOOLEAN; } | for_expression _OF_ rule_set { if ($1.type == EXPRESSION_TYPE_INTEGER && $1.value.integer > $3) { yywarning(yyscanner, "expression always false - requesting %" PRId64 " of %" PRId64 ".", $1.value.integer, $3); } yr_parser_emit_with_arg(yyscanner, OP_OF, OF_RULE_SET, NULL, NULL); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | primary_expression '%' _OF_ string_set { check_type($1, EXPRESSION_TYPE_INTEGER, "%"); // The value of primary_expression can be undefined because // it could be a variable for which don't know the value during // compiling time. However, if the value is defined it should be // in the range [1,100]. if (!IS_UNDEFINED($1.value.integer) && ($1.value.integer < 1 || $1.value.integer > 100)) { yr_compiler_set_error_extra_info( compiler, "percentage must be between 1 and 100 (inclusive)"); fail_with_error(ERROR_INVALID_PERCENTAGE); } if (!IS_UNDEFINED($1.value.integer)) { $$.required_strings.count = 1; } else { $$.required_strings.count = 0; } yr_parser_emit_with_arg(yyscanner, OP_OF_PERCENT, OF_STRING_SET, NULL, NULL); } | primary_expression '%' _OF_ rule_set { check_type($1, EXPRESSION_TYPE_INTEGER, "%"); // The value of primary_expression can be undefined because // it could be a variable for which don't know the value during // compiling time. However, if the value is defined it should be // in the range [1,100]. if (!IS_UNDEFINED($1.value.integer) && ($1.value.integer < 1 || $1.value.integer > 100)) { yr_compiler_set_error_extra_info( compiler, "percentage must be between 1 and 100 (inclusive)"); fail_with_error(ERROR_INVALID_PERCENTAGE); } yr_parser_emit_with_arg(yyscanner, OP_OF_PERCENT, OF_RULE_SET, NULL, NULL); } | for_expression _OF_ string_set _IN_ range { if ($1.type == EXPRESSION_TYPE_INTEGER && $1.value.integer > $3) { yywarning(yyscanner, "expression always false - requesting %" PRId64 " of %" PRId64 ".", $1.value.integer, $3); } if (($1.type == EXPRESSION_TYPE_INTEGER && $1.value.integer > 0) || ($1.type == EXPRESSION_TYPE_QUANTIFIER && ($1.value.integer == FOR_EXPRESSION_ALL || $1.value.integer == FOR_EXPRESSION_ANY))) { $$.required_strings.count = 1; } else { $$.required_strings.count = 0; } yr_parser_emit(yyscanner, OP_OF_FOUND_IN, NULL); $$.type = EXPRESSION_TYPE_BOOLEAN; } | for_expression _OF_ string_set _AT_ primary_expression { if ($5.type != EXPRESSION_TYPE_INTEGER) { yr_compiler_set_error_extra_info(compiler, "at expression must be an integer"); fail_with_error(ERROR_INVALID_VALUE); } if ($1.type == EXPRESSION_TYPE_INTEGER && $1.value.integer > $3) { yywarning(yyscanner, "expression always false - requesting %" PRId64 " of %" PRId64 ".", $1.value.integer, $3); } // Both of these are warnings: // // "N of them at 0" where N > 1 // //"all of them at 0" where there is more than 1 in "them". // // This means you can do "all of them at 0" if you only have one string // defined in the set. if (($1.type == EXPRESSION_TYPE_INTEGER && !IS_UNDEFINED($1.value.integer) && $1.value.integer > 1) || ($1.type == EXPRESSION_TYPE_QUANTIFIER && $1.value.integer == FOR_EXPRESSION_ALL && $3 > 1)) { yywarning(yyscanner, "multiple strings at an offset is usually false."); } if (($1.type == EXPRESSION_TYPE_INTEGER && $1.value.integer > 0) || ($1.type == EXPRESSION_TYPE_QUANTIFIER && ($1.value.integer == FOR_EXPRESSION_ALL || $1.value.integer == FOR_EXPRESSION_ANY))) { $$.required_strings.count = 1; } else { $$.required_strings.count = 0; } yr_parser_emit(yyscanner, OP_OF_FOUND_AT, NULL); $$.type = EXPRESSION_TYPE_BOOLEAN; } | _NOT_ boolean_expression { yr_parser_emit(yyscanner, OP_NOT, NULL); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | _DEFINED_ boolean_expression { yr_parser_emit(yyscanner, OP_DEFINED, NULL); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | boolean_expression _AND_ { YR_FIXUP* fixup; YR_ARENA_REF jmp_offset_ref; fail_if_error(yr_parser_emit_with_arg_int32( yyscanner, OP_JFALSE, 0, // still don't know the jump offset, use 0 for now. NULL, &jmp_offset_ref)); // Create a fixup entry for the jump and push it in the stack. fixup = (YR_FIXUP*) yr_malloc(sizeof(YR_FIXUP)); if (fixup == NULL) fail_with_error(ERROR_INSUFFICIENT_MEMORY); fixup->ref = jmp_offset_ref; fixup->next = compiler->fixup_stack_head; compiler->fixup_stack_head = fixup; } boolean_expression { YR_FIXUP* fixup; fail_if_error(yr_parser_emit(yyscanner, OP_AND, NULL)); fixup = compiler->fixup_stack_head; int32_t* jmp_offset_addr = (int32_t*) yr_arena_ref_to_ptr( compiler->arena, &fixup->ref); int32_t jmp_offset = \ yr_arena_get_current_offset(compiler->arena, YR_CODE_SECTION) - fixup->ref.offset + 1; memcpy(jmp_offset_addr, &jmp_offset, sizeof(jmp_offset)); // Remove fixup from the stack. compiler->fixup_stack_head = fixup->next; yr_free(fixup); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = $4.required_strings.count + $1.required_strings.count; } | boolean_expression _OR_ { YR_FIXUP* fixup; YR_ARENA_REF jmp_offset_ref; fail_if_error(yr_parser_emit_with_arg_int32( yyscanner, OP_JTRUE, 0, // still don't know the jump destination, use 0 for now. NULL, &jmp_offset_ref)); fixup = (YR_FIXUP*) yr_malloc(sizeof(YR_FIXUP)); if (fixup == NULL) fail_with_error(ERROR_INSUFFICIENT_MEMORY); fixup->ref = jmp_offset_ref; fixup->next = compiler->fixup_stack_head; compiler->fixup_stack_head = fixup; } boolean_expression { YR_FIXUP* fixup; fail_if_error(yr_parser_emit(yyscanner, OP_OR, NULL)); fixup = compiler->fixup_stack_head; int32_t jmp_offset = \ yr_arena_get_current_offset(compiler->arena, YR_CODE_SECTION) - fixup->ref.offset + 1; int32_t* jmp_offset_addr = (int32_t*) yr_arena_ref_to_ptr( compiler->arena, &fixup->ref); memcpy(jmp_offset_addr, &jmp_offset, sizeof(jmp_offset)); // Remove fixup from the stack. compiler->fixup_stack_head = fixup->next; yr_free(fixup); $$.type = EXPRESSION_TYPE_BOOLEAN; // Set required string count to minimum from both parts if ($1.required_strings.count > $4.required_strings.count) { $$.required_strings.count = $4.required_strings.count; } else { $$.required_strings.count = $1.required_strings.count; } } | primary_expression _LT_ primary_expression { fail_if_error(yr_parser_reduce_operation( yyscanner, "<", $1, $3)); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | primary_expression _GT_ primary_expression { fail_if_error(yr_parser_reduce_operation( yyscanner, ">", $1, $3)); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | primary_expression _LE_ primary_expression { fail_if_error(yr_parser_reduce_operation( yyscanner, "<=", $1, $3)); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | primary_expression _GE_ primary_expression { fail_if_error(yr_parser_reduce_operation( yyscanner, ">=", $1, $3)); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | primary_expression _EQ_ primary_expression { fail_if_error(yr_parser_reduce_operation( yyscanner, "==", $1, $3)); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | primary_expression _NEQ_ primary_expression { fail_if_error(yr_parser_reduce_operation( yyscanner, "!=", $1, $3)); $$.type = EXPRESSION_TYPE_BOOLEAN; $$.required_strings.count = 0; } | primary_expression { $$ = $1; } |'(' expression ')' { $$ = $2; } ; for_iteration : for_variables _IN_ iterator { $$ = FOR_ITERATION_ITERATOR; } | _OF_ string_iterator { int var_frame; int result = ERROR_SUCCESS; if (compiler->loop_for_of_var_index != -1) result = ERROR_NESTED_FOR_OF_LOOP; fail_if_error(result); // Simulate that we have 1 variable with string loops compiler->loop[compiler->loop_index].vars_count = 1; // Set where we can find our string in case $ is in // the body of the loop var_frame = _yr_compiler_get_var_frame(compiler); compiler->loop_for_of_var_index = var_frame + compiler->loop[compiler->loop_index].vars_internal_count; $$ = FOR_ITERATION_STRING_SET; } ; for_variables : _IDENTIFIER_ { int result = ERROR_SUCCESS; YR_LOOP_CONTEXT* loop_ctx = &compiler->loop[compiler->loop_index]; if (yr_parser_lookup_loop_variable(yyscanner, $1, NULL) >= 0) { yr_compiler_set_error_extra_info(compiler, $1); yr_free($1); result = ERROR_DUPLICATED_LOOP_IDENTIFIER; } fail_if_error(result); loop_ctx->vars[loop_ctx->vars_count++].identifier.ptr = $1; assert(loop_ctx->vars_count <= YR_MAX_LOOP_VARS); } | for_variables ',' _IDENTIFIER_ { int result = ERROR_SUCCESS; YR_LOOP_CONTEXT* loop_ctx = &compiler->loop[compiler->loop_index]; if (loop_ctx->vars_count == YR_MAX_LOOP_VARS) { yr_compiler_set_error_extra_info(compiler, "too many loop variables"); yr_free($3); result = ERROR_SYNTAX_ERROR; } else if (yr_parser_lookup_loop_variable(yyscanner, $3, NULL) >= 0) { yr_compiler_set_error_extra_info(compiler, $3); yr_free($3); result = ERROR_DUPLICATED_LOOP_IDENTIFIER; } fail_if_error(result); loop_ctx->vars[loop_ctx->vars_count++].identifier.ptr = $3; } ; iterator : identifier { YR_LOOP_CONTEXT* loop_ctx = &compiler->loop[compiler->loop_index]; // Initially we assume that the identifier is from a non-iterable type, // this will change later if it's iterable. int result = ERROR_WRONG_TYPE; if ($1.type == EXPRESSION_TYPE_OBJECT) { switch($1.value.object->type) { case OBJECT_TYPE_ARRAY: // If iterating an array the loop must define a single variable // that will hold the current item. If a different number of // variables were defined that's an error. if (loop_ctx->vars_count == 1) { loop_ctx->vars[0].type = EXPRESSION_TYPE_OBJECT; loop_ctx->vars[0].value.object = \ object_as_array($1.value.object)->prototype_item; result = yr_parser_emit(yyscanner, OP_ITER_START_ARRAY, NULL); } else { yr_compiler_set_error_extra_info_fmt( compiler, "iterator for \"%s\" yields a single item on each iteration" ", but the loop expects %d", expression_identifier($1), loop_ctx->vars_count); result = ERROR_SYNTAX_ERROR; } break; case OBJECT_TYPE_DICTIONARY: // If iterating a dictionary the loop must define exactly two // variables, one for the key and another for the value . If a // different number of variables were defined that's an error. if (loop_ctx->vars_count == 2) { loop_ctx->vars[0].type = EXPRESSION_TYPE_STRING; loop_ctx->vars[0].value.sized_string_ref = YR_ARENA_NULL_REF; loop_ctx->vars[1].type = EXPRESSION_TYPE_OBJECT; loop_ctx->vars[1].value.object = \ object_as_array($1.value.object)->prototype_item; result = yr_parser_emit(yyscanner, OP_ITER_START_DICT, NULL); } else { yr_compiler_set_error_extra_info_fmt( compiler, "iterator for \"%s\" yields a key,value pair item on each iteration", expression_identifier($1)); result = ERROR_SYNTAX_ERROR; } break; } } if (result == ERROR_WRONG_TYPE) { yr_compiler_set_error_extra_info_fmt( compiler, "identifier \"%s\" is not iterable", expression_identifier($1)); } fail_if_error(result); } | set { int result = ERROR_SUCCESS; YR_LOOP_CONTEXT* loop_ctx = &compiler->loop[compiler->loop_index]; if (loop_ctx->vars_count == 1) { loop_ctx->vars[0].type = $1.type; if ($1.type == EXPRESSION_TYPE_STRING) loop_ctx->vars[0].value.sized_string_ref = YR_ARENA_NULL_REF; else loop_ctx->vars[0].value.integer = YR_UNDEFINED; } else { yr_compiler_set_error_extra_info_fmt( compiler, "iterator yields one value on each iteration " ", but the loop expects %d", loop_ctx->vars_count); result = ERROR_SYNTAX_ERROR; } fail_if_error(result); } ; set : '(' enumeration ')' { // $2.count contains the number of items in the enumeration fail_if_error(yr_parser_emit_push_const(yyscanner, $2.count)); if ($2.type == EXPRESSION_TYPE_INTEGER) { fail_if_error(yr_parser_emit( yyscanner, OP_ITER_START_INT_ENUM, NULL)); } else { fail_if_error(yr_parser_emit( yyscanner, OP_ITER_START_TEXT_STRING_SET, NULL)); } $$.type = $2.type; } | range { fail_if_error(yr_parser_emit( yyscanner, OP_ITER_START_INT_RANGE, NULL)); $$.type = EXPRESSION_TYPE_INTEGER; } ; range : '(' primary_expression _DOT_DOT_ primary_expression ')' { int result = ERROR_SUCCESS; if ($2.type != EXPRESSION_TYPE_INTEGER) { yr_compiler_set_error_extra_info( compiler, "wrong type for range's lower bound"); result = ERROR_WRONG_TYPE; } if ($4.type != EXPRESSION_TYPE_INTEGER) { yr_compiler_set_error_extra_info( compiler, "wrong type for range's upper bound"); result = ERROR_WRONG_TYPE; } // If we can statically determine lower and upper bounds, ensure // lower < upper. Check for upper bound here because some things (like // string count) are EXPRESSION_TYPE_INTEGER. if ($2.value.integer != YR_UNDEFINED && $4.value.integer != YR_UNDEFINED) { if ($2.value.integer > $4.value.integer) { yr_compiler_set_error_extra_info( compiler, "range lower bound must be less than upper bound"); result = ERROR_INVALID_VALUE; } else if ($2.value.integer < 0) { yr_compiler_set_error_extra_info( compiler, "range lower bound can not be negative"); result = ERROR_INVALID_VALUE; } } fail_if_error(result); } ; enumeration : primary_expression { int result = ERROR_SUCCESS; if ($1.type != EXPRESSION_TYPE_INTEGER && $1.type != EXPRESSION_TYPE_STRING) { yr_compiler_set_error_extra_info( compiler, "wrong type for enumeration item"); result = ERROR_WRONG_TYPE; } fail_if_error(result); $$.type = $1.type; $$.count = 1; } | enumeration ',' primary_expression { int result = ERROR_SUCCESS; if ($3.type != $1.type) { yr_compiler_set_error_extra_info( compiler, "enumerations must be all the same type"); result = ERROR_WRONG_TYPE; } fail_if_error(result); $$.type = $1.type; $$.count = $1.count + 1; } ; string_iterator : string_set { fail_if_error(yr_parser_emit_push_const(yyscanner, $1)); fail_if_error(yr_parser_emit(yyscanner, OP_ITER_START_STRING_SET, NULL)); } ; string_set : '(' { // Push end-of-list marker yr_parser_emit_push_const(yyscanner, YR_UNDEFINED); } string_enumeration ')' { $$ = $3; } | _THEM_ { fail_if_error(yr_parser_emit_push_const(yyscanner, YR_UNDEFINED)); int count = 0; fail_if_error(yr_parser_emit_pushes_for_strings( yyscanner, "$*", &count)); $$ = count; } ; string_enumeration : string_enumeration_item { $$ = $1; } | string_enumeration ',' string_enumeration_item { $$ = $1 + $3; } ; string_enumeration_item : _STRING_IDENTIFIER_ { int count = 0; int result = yr_parser_emit_pushes_for_strings(yyscanner, $1, &count); yr_free($1); fail_if_error(result); $$ = count; } | _STRING_IDENTIFIER_WITH_WILDCARD_ { int count = 0; int result = yr_parser_emit_pushes_for_strings(yyscanner, $1, &count); yr_free($1); fail_if_error(result); $$ = count; } ; rule_set : '(' { // Push end-of-list marker yr_parser_emit_push_const(yyscanner, YR_UNDEFINED); } rule_enumeration ')' { $$ = $3; } ; rule_enumeration : rule_enumeration_item { $$ = $1; } | rule_enumeration ',' rule_enumeration_item { $$ = $1 + $3; } ; rule_enumeration_item : _IDENTIFIER_ { int result = ERROR_SUCCESS; YR_NAMESPACE* ns = (YR_NAMESPACE*) yr_arena_get_ptr( compiler->arena, YR_NAMESPACES_TABLE, compiler->current_namespace_idx * sizeof(struct YR_NAMESPACE)); uint32_t rule_idx = yr_hash_table_lookup_uint32( compiler->rules_table, $1, ns->name); if (rule_idx != UINT32_MAX) { result = yr_parser_emit_with_arg( yyscanner, OP_PUSH_RULE, rule_idx, NULL, NULL); } else { yr_compiler_set_error_extra_info(compiler, $1); result = ERROR_UNDEFINED_IDENTIFIER; } yr_free($1); fail_if_error(result); $$ = 1; } | _IDENTIFIER_ '*' { int count = 0; YR_NAMESPACE* ns = (YR_NAMESPACE*) yr_arena_get_ptr( compiler->arena, YR_NAMESPACES_TABLE, compiler->current_namespace_idx * sizeof(struct YR_NAMESPACE)); yr_hash_table_add_uint32( compiler->wildcard_identifiers_table, $1, ns->name, 1); int result = yr_parser_emit_pushes_for_rules(yyscanner, $1, &count); yr_free($1); fail_if_error(result); $$ = count; } ; for_expression : primary_expression { if ($1.type == EXPRESSION_TYPE_INTEGER && !IS_UNDEFINED($1.value.integer)) { if ($1.value.integer == 0) { yywarning(yyscanner, "consider using \"none\" keyword, it is less ambiguous."); } if ($1.value.integer < 0) { yr_compiler_set_error_extra_info_fmt(compiler, "%" PRId64, $1.value.integer); fail_with_error(ERROR_INVALID_VALUE); } } if ($1.type == EXPRESSION_TYPE_FLOAT) { yr_compiler_set_error_extra_info_fmt(compiler, "%a", $1.value.double_); fail_with_error(ERROR_INVALID_VALUE); } if ($1.type == EXPRESSION_TYPE_STRING) { SIZED_STRING* ss = yr_arena_ref_to_ptr(compiler->arena, &$1.value.sized_string_ref); // If the expression is an external string variable we need to get // it some other way. if (ss != NULL) { yr_compiler_set_error_extra_info_fmt(compiler, "%s", ss->c_string); } else { yr_compiler_set_error_extra_info(compiler, "string in for_expression is invalid"); } fail_with_error(ERROR_INVALID_VALUE); } if ($1.type == EXPRESSION_TYPE_REGEXP) { yr_compiler_set_error_extra_info(compiler, "regexp in for_expression is invalid"); fail_with_error(ERROR_INVALID_VALUE); } $$.value.integer = $1.value.integer; } | for_quantifier { $$.value.integer = $1.value.integer; } ; for_quantifier : _ALL_ { yr_parser_emit_push_const(yyscanner, YR_UNDEFINED); $$.type = EXPRESSION_TYPE_QUANTIFIER; $$.value.integer = FOR_EXPRESSION_ALL; } | _ANY_ { yr_parser_emit_push_const(yyscanner, 1); $$.type = EXPRESSION_TYPE_QUANTIFIER; $$.value.integer = FOR_EXPRESSION_ANY; } | _NONE_ { yr_parser_emit_push_const(yyscanner, 0); $$.type = EXPRESSION_TYPE_QUANTIFIER; $$.value.integer = FOR_EXPRESSION_NONE; } ; primary_expression : '(' primary_expression ')' { $$ = $2; } | _FILESIZE_ { fail_if_error(yr_parser_emit( yyscanner, OP_FILESIZE, NULL)); $$.type = EXPRESSION_TYPE_INTEGER; $$.value.integer = YR_UNDEFINED; } | _ENTRYPOINT_ { yywarning(yyscanner, "using deprecated \"entrypoint\" keyword. Use the \"entry_point\" " "function from PE module instead."); fail_if_error(yr_parser_emit( yyscanner, OP_ENTRYPOINT, NULL)); $$.type = EXPRESSION_TYPE_INTEGER; $$.value.integer = YR_UNDEFINED; } | _INTEGER_FUNCTION_ '(' primary_expression ')' { check_type($3, EXPRESSION_TYPE_INTEGER, "intXXXX or uintXXXX"); // _INTEGER_FUNCTION_ could be any of int8, int16, int32, uint8, // uint32, etc. $1 contains an index that added to OP_READ_INT results // in the proper OP_INTXX opcode. fail_if_error(yr_parser_emit( yyscanner, (uint8_t) (OP_READ_INT + $1), NULL)); $$.type = EXPRESSION_TYPE_INTEGER; $$.value.integer = YR_UNDEFINED; } | _NUMBER_ { fail_if_error(yr_parser_emit_push_const(yyscanner, $1)); $$.type = EXPRESSION_TYPE_INTEGER; $$.value.integer = $1; } | _DOUBLE_ { fail_if_error(yr_parser_emit_with_arg_double( yyscanner, OP_PUSH, $1, NULL, NULL)); $$.type = EXPRESSION_TYPE_FLOAT; } | _TEXT_STRING_ { YR_ARENA_REF ref; int result = _yr_compiler_store_data( compiler, $1, $1->length + sizeof(SIZED_STRING), &ref); yr_free($1); if (result == ERROR_SUCCESS) result = yr_parser_emit_with_arg_reloc( yyscanner, OP_PUSH, yr_arena_ref_to_ptr(compiler->arena, &ref), NULL, NULL); fail_if_error(result); $$.type = EXPRESSION_TYPE_STRING; $$.value.sized_string_ref = ref; } | _STRING_COUNT_ _IN_ range { int result = yr_parser_reduce_string_identifier( yyscanner, $1, OP_COUNT_IN, YR_UNDEFINED); yr_free($1); fail_if_error(result); $$.type = EXPRESSION_TYPE_INTEGER; $$.value.integer = YR_UNDEFINED; } | _STRING_COUNT_ { int result = yr_parser_reduce_string_identifier( yyscanner, $1, OP_COUNT, YR_UNDEFINED); yr_free($1); fail_if_error(result); $$.type = EXPRESSION_TYPE_INTEGER; $$.value.integer = YR_UNDEFINED; } | _STRING_OFFSET_ '[' primary_expression ']' { int result = yr_parser_reduce_string_identifier( yyscanner, $1, OP_OFFSET, YR_UNDEFINED); yr_free($1); fail_if_error(result); $$.type = EXPRESSION_TYPE_INTEGER; $$.value.integer = YR_UNDEFINED; } | _STRING_OFFSET_ { int result = yr_parser_emit_push_const(yyscanner, 1); if (result == ERROR_SUCCESS) result = yr_parser_reduce_string_identifier( yyscanner, $1, OP_OFFSET, YR_UNDEFINED); yr_free($1); fail_if_error(result); $$.type = EXPRESSION_TYPE_INTEGER; $$.value.integer = YR_UNDEFINED; } | _STRING_LENGTH_ '[' primary_expression ']' { int result = yr_parser_reduce_string_identifier( yyscanner, $1, OP_LENGTH, YR_UNDEFINED); yr_free($1); fail_if_error(result); $$.type = EXPRESSION_TYPE_INTEGER; $$.value.integer = YR_UNDEFINED; } | _STRING_LENGTH_ { int result = yr_parser_emit_push_const(yyscanner, 1); if (result == ERROR_SUCCESS) result = yr_parser_reduce_string_identifier( yyscanner, $1, OP_LENGTH, YR_UNDEFINED); yr_free($1); fail_if_error(result); $$.type = EXPRESSION_TYPE_INTEGER; $$.value.integer = YR_UNDEFINED; } | identifier { int result = ERROR_SUCCESS; if ($1.type == EXPRESSION_TYPE_OBJECT) { result = yr_parser_emit( yyscanner, OP_OBJ_VALUE, NULL); switch($1.value.object->type) { case OBJECT_TYPE_INTEGER: $$.type = EXPRESSION_TYPE_INTEGER; $$.value.integer = $1.value.object->value.i; break; case OBJECT_TYPE_FLOAT: $$.type = EXPRESSION_TYPE_FLOAT; break; case OBJECT_TYPE_STRING: $$.type = EXPRESSION_TYPE_STRING; $$.value.sized_string_ref = YR_ARENA_NULL_REF; break; default: // In a primary expression any identifier that corresponds to an // object must be of type integer, float or string. If "foobar" is // either a function, structure, dictionary or array you can not // use it as: // condition: foobar yr_compiler_set_error_extra_info_fmt( compiler, "wrong usage of identifier \"%s\"", expression_identifier($1)); result = ERROR_WRONG_TYPE; } } else { $$ = $1; } fail_if_error(result); } | '-' primary_expression %prec UNARY_MINUS { int result = ERROR_SUCCESS; check_type($2, EXPRESSION_TYPE_INTEGER | EXPRESSION_TYPE_FLOAT, "-"); if ($2.type == EXPRESSION_TYPE_INTEGER) { $$.type = EXPRESSION_TYPE_INTEGER; $$.value.integer = ($2.value.integer == YR_UNDEFINED) ? YR_UNDEFINED : -($2.value.integer); result = yr_parser_emit(yyscanner, OP_INT_MINUS, NULL); } else if ($2.type == EXPRESSION_TYPE_FLOAT) { $$.type = EXPRESSION_TYPE_FLOAT; result = yr_parser_emit(yyscanner, OP_DBL_MINUS, NULL); } fail_if_error(result); } | primary_expression '+' primary_expression { int result = yr_parser_reduce_operation( yyscanner, "+", $1, $3); if ($1.type == EXPRESSION_TYPE_INTEGER && $3.type == EXPRESSION_TYPE_INTEGER) { int64_t i1 = $1.value.integer; int64_t i2 = $3.value.integer; if (!IS_UNDEFINED(i1) && !IS_UNDEFINED(i2) && ( (i2 > 0 && i1 > INT64_MAX - i2) || (i2 < 0 && i1 < INT64_MIN - i2) )) { yr_compiler_set_error_extra_info_fmt( compiler, "%" PRId64 " + %" PRId64, i1, i2); result = ERROR_INTEGER_OVERFLOW; } else { $$.value.integer = OPERATION(+, i1, i2); $$.type = EXPRESSION_TYPE_INTEGER; } } else { $$.type = EXPRESSION_TYPE_FLOAT; } fail_if_error(result); } | primary_expression '-' primary_expression { int result = yr_parser_reduce_operation( yyscanner, "-", $1, $3); if ($1.type == EXPRESSION_TYPE_INTEGER && $3.type == EXPRESSION_TYPE_INTEGER) { int64_t i1 = $1.value.integer; int64_t i2 = $3.value.integer; if (!IS_UNDEFINED(i1) && !IS_UNDEFINED(i2) && ( (i2 < 0 && i1 > INT64_MAX + i2) || (i2 > 0 && i1 < INT64_MIN + i2) )) { yr_compiler_set_error_extra_info_fmt( compiler, "%" PRId64 " - %" PRId64, i1, i2); result = ERROR_INTEGER_OVERFLOW; } else { $$.value.integer = OPERATION(-, i1, i2); $$.type = EXPRESSION_TYPE_INTEGER; } } else { $$.type = EXPRESSION_TYPE_FLOAT; } fail_if_error(result); } | primary_expression '*' primary_expression { int result = yr_parser_reduce_operation( yyscanner, "*", $1, $3); if ($1.type == EXPRESSION_TYPE_INTEGER && $3.type == EXPRESSION_TYPE_INTEGER) { int64_t i1 = $1.value.integer; int64_t i2 = $3.value.integer; if (!IS_UNDEFINED(i1) && !IS_UNDEFINED(i2) && ( i2 != 0 && llabs(i1) > INT64_MAX / llabs(i2) )) { yr_compiler_set_error_extra_info_fmt( compiler, "%" PRId64 " * %" PRId64, i1, i2); result = ERROR_INTEGER_OVERFLOW; } else { $$.value.integer = OPERATION(*, i1, i2); $$.type = EXPRESSION_TYPE_INTEGER; } } else { $$.type = EXPRESSION_TYPE_FLOAT; } fail_if_error(result); } | primary_expression '\\' primary_expression { int result = yr_parser_reduce_operation( yyscanner, "\\", $1, $3); if ($1.type == EXPRESSION_TYPE_INTEGER && $3.type == EXPRESSION_TYPE_INTEGER) { if ($3.value.integer != 0) { $$.value.integer = OPERATION(/, $1.value.integer, $3.value.integer); $$.type = EXPRESSION_TYPE_INTEGER; } else { result = ERROR_DIVISION_BY_ZERO; } } else { $$.type = EXPRESSION_TYPE_FLOAT; } fail_if_error(result); } | primary_expression '%' primary_expression { check_type($1, EXPRESSION_TYPE_INTEGER, "%"); check_type($3, EXPRESSION_TYPE_INTEGER, "%"); fail_if_error(yr_parser_emit(yyscanner, OP_MOD, NULL)); if ($3.value.integer != 0) { $$.value.integer = OPERATION(%, $1.value.integer, $3.value.integer); $$.type = EXPRESSION_TYPE_INTEGER; } else { fail_if_error(ERROR_DIVISION_BY_ZERO); } } | primary_expression '^' primary_expression { check_type($1, EXPRESSION_TYPE_INTEGER, "^"); check_type($3, EXPRESSION_TYPE_INTEGER, "^"); fail_if_error(yr_parser_emit(yyscanner, OP_BITWISE_XOR, NULL)); $$.type = EXPRESSION_TYPE_INTEGER; $$.value.integer = OPERATION(^, $1.value.integer, $3.value.integer); } | primary_expression '&' primary_expression { check_type($1, EXPRESSION_TYPE_INTEGER, "^"); check_type($3, EXPRESSION_TYPE_INTEGER, "^"); fail_if_error(yr_parser_emit(yyscanner, OP_BITWISE_AND, NULL)); $$.type = EXPRESSION_TYPE_INTEGER; $$.value.integer = OPERATION(&, $1.value.integer, $3.value.integer); } | primary_expression '|' primary_expression { check_type($1, EXPRESSION_TYPE_INTEGER, "|"); check_type($3, EXPRESSION_TYPE_INTEGER, "|"); fail_if_error(yr_parser_emit(yyscanner, OP_BITWISE_OR, NULL)); $$.type = EXPRESSION_TYPE_INTEGER; $$.value.integer = OPERATION(|, $1.value.integer, $3.value.integer); } | '~' primary_expression { check_type($2, EXPRESSION_TYPE_INTEGER, "~"); fail_if_error(yr_parser_emit(yyscanner, OP_BITWISE_NOT, NULL)); $$.type = EXPRESSION_TYPE_INTEGER; $$.value.integer = ($2.value.integer == YR_UNDEFINED) ? YR_UNDEFINED : ~($2.value.integer); } | primary_expression _SHIFT_LEFT_ primary_expression { int result; check_type($1, EXPRESSION_TYPE_INTEGER, "<<"); check_type($3, EXPRESSION_TYPE_INTEGER, "<<"); result = yr_parser_emit(yyscanner, OP_SHL, NULL); if (!IS_UNDEFINED($3.value.integer) && $3.value.integer < 0) result = ERROR_INVALID_OPERAND; else if (!IS_UNDEFINED($3.value.integer) && $3.value.integer >= 64) $$.value.integer = 0; else $$.value.integer = OPERATION(<<, $1.value.integer, $3.value.integer); $$.type = EXPRESSION_TYPE_INTEGER; fail_if_error(result); } | primary_expression _SHIFT_RIGHT_ primary_expression { int result; check_type($1, EXPRESSION_TYPE_INTEGER, ">>"); check_type($3, EXPRESSION_TYPE_INTEGER, ">>"); result = yr_parser_emit(yyscanner, OP_SHR, NULL); if (!IS_UNDEFINED($3.value.integer) && $3.value.integer < 0) result = ERROR_INVALID_OPERAND; else if (!IS_UNDEFINED($3.value.integer) && $3.value.integer >= 64) $$.value.integer = 0; else $$.value.integer = OPERATION(<<, $1.value.integer, $3.value.integer); $$.type = EXPRESSION_TYPE_INTEGER; fail_if_error(result); } | regexp { $$ = $1; } ; %% yara-4.5.3/libyara/hash.c000066400000000000000000000302261501365277300152050ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include // Constant-time left rotate that does not invoke undefined behavior. // http://blog.regehr.org/archives/1063 static uint32_t rotl32(uint32_t x, uint32_t shift) { assert(shift < 32); return (x << shift) | (x >> (-shift & 31)); } #define ROTATE_INT32(x, shift) rotl32(x, shift % 32) uint32_t byte_to_int32[] = { 0xC3113E7F, 0x4C353C5F, 0x7423810B, 0x258D264E, 0xDAD39DED, 0x75D0B694, 0x98CE1216, 0x93334482, 0xC5C48EA5, 0xF57E0E8B, 0x5D7F3723, 0x396B1B24, 0xA8883D9F, 0xB2A74A00, 0xF8E171AE, 0x3F01FBAB, 0x5C1840CB, 0xDDD833C4, 0x8D8CCA34, 0x32EF223A, 0x1A05B871, 0x9A9B6BFC, 0x50406A0C, 0xE7E1FC04, 0x5E07D7F6, 0x80B83660, 0x20892A62, 0xB2C6FEA6, 0x6CEC7CAA, 0x182F764B, 0x3B0353E7, 0x57FC2520, 0x4B6812D4, 0xACB654E4, 0x23C75C04, 0xB1DCD731, 0xE3AF0733, 0xF2366D39, 0xC729671B, 0xFF3BE6F2, 0xABA37E34, 0x3CDAFA38, 0xAAD18D03, 0xA8D35345, 0x08E9A92C, 0xF9324059, 0x42D821BE, 0x1BC152DD, 0x5588811C, 0x874A1F9A, 0x6E83E9CD, 0xDA6F3AF8, 0x965D4670, 0xA7A565C0, 0x68D8A9AF, 0xFC8FD8FD, 0x8FF99FF9, 0x4C9B42AE, 0x2D066A8D, 0x4D1802F7, 0x557032B2, 0x12BCF371, 0xDC29D5AE, 0x72EA361F, 0xE2835B0B, 0xDFC58966, 0x13B0F34D, 0x3FA02BCD, 0xBF282E3D, 0x7DC877F5, 0xF4848A32, 0x861E35F5, 0x7FFA0D7F, 0x515F2E4E, 0x6B235D5C, 0x55F46E24, 0x35AD2C99, 0x072654A8, 0x05163F0F, 0x9317B11A, 0xAED1FC10, 0x989444F0, 0xDB3E1814, 0x446C0CF1, 0x660BF511, 0x2F227D3A, 0xFDBA0539, 0xC649E621, 0x5204D7CE, 0x5FA386D0, 0xE5F22005, 0x97B6C8A1, 0x4AB69EC2, 0x5C7CA70D, 0x39A48EC6, 0x7BACF378, 0x8D0ED3D1, 0xE39DE582, 0xC5FBE2AB, 0x37E3D2D0, 0x06F44724, 0x73144144, 0xBA57E905, 0xB05B4307, 0xAEED8D97, 0xA68CCAC4, 0xE30DA57E, 0xED0F194B, 0x8C2B9B7A, 0x814575D5, 0x79588493, 0x81D3712A, 0x3FA892F2, 0x80F0BB94, 0x44EAF51A, 0x4E05F1D4, 0xFC69F858, 0x775E8D60, 0x22B20DD7, 0x170A87EA, 0x1077DE52, 0x3D5EC9FB, 0x0B6EB1E5, 0xF2F9CCAF, 0xA76C7DEB, 0xD8C2D873, 0xF438C592, 0x6239FEEC, 0x26D3D2A9, 0x30F6FADF, 0x4B2984CC, 0x6257F3DA, 0x0E0583E2, 0x143E5E61, 0xBB2732BF, 0x9653217A, 0x027A84EA, 0x95C9AE8B, 0x89B8B82B, 0x9F286485, 0x29F622FE, 0x52A3196B, 0x8392D95F, 0x33A79167, 0xF5DEE92A, 0x6E397DB9, 0x11931C01, 0x8DD2CD3B, 0xF9E6003D, 0xAB955AF4, 0xD38725F9, 0xDCF6F8AE, 0x7667A958, 0xE67AD995, 0xB7CF979A, 0xD88EBE5B, 0x5BA889F0, 0x078BDD90, 0x447238F9, 0x3135F672, 0x187B95A8, 0x0B7D5751, 0xACD59D2A, 0x9C5D1929, 0x579E5022, 0xEA90499B, 0x59901800, 0x82237DB5, 0x7A375509, 0xACA9A22A, 0xEC96E649, 0x69339DB0, 0x081D0D9B, 0xD72FB8B9, 0xA4184653, 0xC057321D, 0xED19CAB9, 0xB48F1E3E, 0xB9DAC51E, 0xDAED2FC7, 0x7598CBBD, 0x208DF346, 0x044BE6EC, 0x1C63E6EB, 0xA15F64C1, 0xE024A061, 0x68309584, 0x0758A68D, 0xF274E9AE, 0x0ABEA0CC, 0xED4FB267, 0x63D6EC46, 0x9F28E026, 0xF0694A17, 0x9D6E9115, 0xC4600FAD, 0x5B121E99, 0xD6B4A13B, 0xF5364B8A, 0x8514B254, 0x0182F8DD, 0xDB09F90B, 0x78C70B32, 0xD8EC3B02, 0x8CD7084D, 0xA4439838, 0x72F35A3D, 0x200B48A5, 0xE2351444, 0xA5552F5F, 0xD8C1E746, 0x0FE5EF3C, 0xB6A47063, 0x61F4E68B, 0x08FED99B, 0x7E461445, 0x43CB8380, 0x28BA03C8, 0x21A7A2E2, 0x43437ED6, 0x2A9E6670, 0x89B4A106, 0xC6C2F4EE, 0x9C4063CC, 0x2FA0DF6C, 0xB54DC409, 0xCF01538F, 0x616431D7, 0x02CB0E4D, 0x44FFF425, 0xAAD5188E, 0x0742E9BC, 0xFFF41353, 0x130F0A15, 0x787BDC10, 0x4A327B72, 0x702989F7, 0x5F704798, 0x8156A1BB, 0x2BCA3E74, 0x1911A8C4, 0x5E1F27D3, 0x07949DC7, 0xF24C2056, 0xB4299EE6, 0x9C7045D9, 0xA8BF6307, 0x7454AAD2, 0x256425E5, 0xD87DEF67, 0xCFE95452, 0xE7548DF7, 0xA84956C7, 0xD8402C60, 0xCFBD0373, 0x6B6CDAFE}; uint32_t yr_hash(uint32_t seed, const void* buffer, size_t len) { const uint8_t* b = (uint8_t*) buffer; uint32_t result = seed; size_t i; if (len == 0) return result; for (i = len - 1; i > 0; i--) { result ^= ROTATE_INT32(byte_to_int32[*b], i); b++; } result ^= byte_to_int32[*b]; return result; } //////////////////////////////////////////////////////////////////////////////// // Return the value associated to a given key and optionally remove it from // the hash table. Key can be any byte sequence, namespace is a null-terminated // string, and remove is a boolean. // static void* _yr_hash_table_lookup( YR_HASH_TABLE* table, const void* key, size_t key_length, const char* ns, int remove) { YR_HASH_TABLE_ENTRY* entry; YR_HASH_TABLE_ENTRY* prev_entry; void* result; uint32_t bucket_index = yr_hash(0, key, key_length); if (ns != NULL) bucket_index = yr_hash(bucket_index, (uint8_t*) ns, strlen(ns)); bucket_index = bucket_index % table->size; prev_entry = NULL; entry = table->buckets[bucket_index]; while (entry != NULL) { int key_match = ((entry->key_length == key_length) && (memcmp(entry->key, key, key_length) == 0)); int ns_match = ((entry->ns == ns) || (entry->ns != NULL && ns != NULL && strcmp(entry->ns, ns) == 0)); if (key_match && ns_match) { result = entry->value; if (remove) { if (prev_entry == NULL) table->buckets[bucket_index] = entry->next; else prev_entry->next = entry->next; if (entry->ns != NULL) yr_free(entry->ns); yr_free(entry->key); yr_free(entry); } return result; } prev_entry = entry; entry = entry->next; } return NULL; } YR_API int yr_hash_table_create(int size, YR_HASH_TABLE** table) { YR_HASH_TABLE* new_table; int i; new_table = (YR_HASH_TABLE*) yr_malloc( sizeof(YR_HASH_TABLE) + size * sizeof(YR_HASH_TABLE_ENTRY*)); if (new_table == NULL) return ERROR_INSUFFICIENT_MEMORY; new_table->size = size; for (i = 0; i < size; i++) new_table->buckets[i] = NULL; *table = new_table; return ERROR_SUCCESS; } YR_API void yr_hash_table_clean( YR_HASH_TABLE* table, YR_HASH_TABLE_FREE_VALUE_FUNC free_value) { YR_HASH_TABLE_ENTRY* entry; YR_HASH_TABLE_ENTRY* next_entry; int i; if (table == NULL) return; for (i = 0; i < table->size; i++) { entry = table->buckets[i]; while (entry != NULL) { next_entry = entry->next; if (free_value != NULL) free_value(entry->value); if (entry->ns != NULL) yr_free(entry->ns); yr_free(entry->key); yr_free(entry); entry = next_entry; } table->buckets[i] = NULL; } } YR_API void yr_hash_table_destroy( YR_HASH_TABLE* table, YR_HASH_TABLE_FREE_VALUE_FUNC free_value) { yr_hash_table_clean(table, free_value); yr_free(table); } YR_API int yr_hash_table_iterate( YR_HASH_TABLE* table, const char* ns, YR_HASH_TABLE_ITERATE_FUNC iterate_func, void* data) { int result; YR_HASH_TABLE_ENTRY* entry; if (table == NULL) return ERROR_INTERNAL_FATAL_ERROR; for (int i = 0; i < table->size; i++) { entry = table->buckets[i]; while (entry != NULL) { if ((entry->ns == NULL && ns == NULL) || (entry->ns != NULL && ns != NULL && !strcmp(entry->ns, ns))) { result = iterate_func( entry->key, entry->key_length, entry->value, data); if (result != ERROR_SUCCESS) return result; } entry = entry->next; } } return ERROR_SUCCESS; } YR_API void* yr_hash_table_lookup_raw_key( YR_HASH_TABLE* table, const void* key, size_t key_length, const char* ns) { return _yr_hash_table_lookup(table, key, key_length, ns, false); } YR_API void* yr_hash_table_remove_raw_key( YR_HASH_TABLE* table, const void* key, size_t key_length, const char* ns) { return _yr_hash_table_lookup(table, key, key_length, ns, true); } YR_API int yr_hash_table_add_raw_key( YR_HASH_TABLE* table, const void* key, size_t key_length, const char* ns, void* value) { YR_HASH_TABLE_ENTRY* entry; uint32_t bucket_index; entry = (YR_HASH_TABLE_ENTRY*) yr_malloc(sizeof(YR_HASH_TABLE_ENTRY)); if (entry == NULL) return ERROR_INSUFFICIENT_MEMORY; entry->key = yr_malloc(key_length); if (entry->key == NULL) { yr_free(entry); return ERROR_INSUFFICIENT_MEMORY; } if (ns != NULL) { entry->ns = yr_strdup(ns); if (entry->ns == NULL) { yr_free(entry->key); yr_free(entry); return ERROR_INSUFFICIENT_MEMORY; } } else { entry->ns = NULL; } entry->key_length = key_length; entry->value = value; memcpy(entry->key, key, key_length); bucket_index = yr_hash(0, key, key_length); if (ns != NULL) bucket_index = yr_hash(bucket_index, (uint8_t*) ns, strlen(ns)); bucket_index = bucket_index % table->size; entry->next = table->buckets[bucket_index]; table->buckets[bucket_index] = entry; return ERROR_SUCCESS; } YR_API void* yr_hash_table_lookup( YR_HASH_TABLE* table, const char* key, const char* ns) { return yr_hash_table_lookup_raw_key(table, (void*) key, strlen(key), ns); } YR_API void* yr_hash_table_remove( YR_HASH_TABLE* table, const char* key, const char* ns) { return yr_hash_table_remove_raw_key(table, (void*) key, strlen(key), ns); } YR_API int yr_hash_table_add( YR_HASH_TABLE* table, const char* key, const char* ns, void* value) { return yr_hash_table_add_raw_key(table, (void*) key, strlen(key), ns, value); } YR_API int yr_hash_table_add_uint32( YR_HASH_TABLE* table, const char* key, const char* ns, uint32_t value) { return yr_hash_table_add_uint32_raw_key( table, (void*) key, strlen(key), ns, value); } YR_API uint32_t yr_hash_table_lookup_uint32( YR_HASH_TABLE* table, const char* key, const char* ns) { return yr_hash_table_lookup_uint32_raw_key( table, (void*) key, strlen(key), ns); } YR_API int yr_hash_table_add_uint32_raw_key( YR_HASH_TABLE* table, const void* key, size_t key_length, const char* ns, uint32_t value) { // Don't allow values equal to UINT32_MAX or UINT32_MAX - 1. if (value >= UINT32_MAX - 1) return ERROR_INVALID_ARGUMENT; // Add +1 to the value in order to avoid putting a NULL pointer in the // hash table once the integer is casted to a pointer. This is undone // by yr_hash_table_lookup_uint32. return yr_hash_table_add_raw_key( table, key, key_length, ns, (void*) (size_t) (value + 1)); } YR_API uint32_t yr_hash_table_lookup_uint32_raw_key( YR_HASH_TABLE* table, const void* key, size_t key_length, const char* ns) { void* ptr = yr_hash_table_lookup_raw_key(table, key, key_length, ns); if (ptr == NULL) return UINT32_MAX; // Remove one from the pointe in order to get the original value. // See comment in yr_hash_table_add_uint32_raw_key. return ((uint32_t) (size_t) (uint8_t*) ptr) - 1; } yara-4.5.3/libyara/hex_grammar.c000066400000000000000000001533041501365277300165570ustar00rootroot00000000000000/* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. 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 . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output, and Bison version. */ #define YYBISON 30802 /* Bison version string. */ #define YYBISON_VERSION "3.8.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 1 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Substitute the variable and function names. */ #define yyparse hex_yyparse #define yylex hex_yylex #define yyerror hex_yyerror #define yydebug hex_yydebug #define yynerrs hex_yynerrs /* First part of user prologue. */ #line 30 "hex_grammar.y" #include #include #include #include #include #include #include #include #define STR_EXPAND(tok) #tok #define STR(tok) STR_EXPAND(tok) #define YYERROR_VERBOSE #define YYMALLOC yr_malloc #define YYFREE yr_free #define mark_as_not_fast_regexp() \ ((RE_AST*) yyget_extra(yyscanner))->flags &= ~RE_FLAGS_FAST_REGEXP #define fail_if(x, error) \ if (x) \ { \ lex_env->last_error = error; \ YYABORT; \ } \ #define destroy_node_if(x, node) \ if (x) \ { \ yr_re_node_destroy(node); \ } \ #line 115 "hex_grammar.c" # ifndef YY_CAST # ifdef __cplusplus # define YY_CAST(Type, Val) static_cast (Val) # define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) # else # define YY_CAST(Type, Val) ((Type) (Val)) # define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) # endif # endif # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # else # define YY_NULLPTR ((void*)0) # endif # endif /* Use api.header.include to #include this header instead of duplicating it here. */ #ifndef YY_HEX_YY_HEX_GRAMMAR_H_INCLUDED # define YY_HEX_YY_HEX_GRAMMAR_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int hex_yydebug; #endif /* Token kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, YYEOF = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ _BYTE_ = 258, /* _BYTE_ */ _MASKED_BYTE_ = 259, /* _MASKED_BYTE_ */ _NOT_BYTE_ = 260, /* _NOT_BYTE_ */ _MASKED_NOT_BYTE_ = 261, /* _MASKED_NOT_BYTE_ */ _NUMBER_ = 262 /* _NUMBER_ */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Token kinds. */ #define YYEMPTY -2 #define YYEOF 0 #define YYerror 256 #define YYUNDEF 257 #define _BYTE_ 258 #define _MASKED_BYTE_ 259 #define _NOT_BYTE_ 260 #define _MASKED_NOT_BYTE_ 261 #define _NUMBER_ 262 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 78 "hex_grammar.y" int64_t integer; RE_NODE *re_node; #line 187 "hex_grammar.c" }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif int hex_yyparse (void *yyscanner, HEX_LEX_ENVIRONMENT *lex_env); #endif /* !YY_HEX_YY_HEX_GRAMMAR_H_INCLUDED */ /* Symbol kind. */ enum yysymbol_kind_t { YYSYMBOL_YYEMPTY = -2, YYSYMBOL_YYEOF = 0, /* "end of file" */ YYSYMBOL_YYerror = 1, /* error */ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ YYSYMBOL__BYTE_ = 3, /* _BYTE_ */ YYSYMBOL__MASKED_BYTE_ = 4, /* _MASKED_BYTE_ */ YYSYMBOL__NOT_BYTE_ = 5, /* _NOT_BYTE_ */ YYSYMBOL__MASKED_NOT_BYTE_ = 6, /* _MASKED_NOT_BYTE_ */ YYSYMBOL__NUMBER_ = 7, /* _NUMBER_ */ YYSYMBOL_8_ = 8, /* '{' */ YYSYMBOL_9_ = 9, /* '}' */ YYSYMBOL_10_ = 10, /* '(' */ YYSYMBOL_11_ = 11, /* ')' */ YYSYMBOL_12_ = 12, /* '[' */ YYSYMBOL_13_ = 13, /* ']' */ YYSYMBOL_14_ = 14, /* '-' */ YYSYMBOL_15_ = 15, /* '|' */ YYSYMBOL_YYACCEPT = 16, /* $accept */ YYSYMBOL_hex_string = 17, /* hex_string */ YYSYMBOL_tokens = 18, /* tokens */ YYSYMBOL_token_sequence = 19, /* token_sequence */ YYSYMBOL_token_or_range = 20, /* token_or_range */ YYSYMBOL_token = 21, /* token */ YYSYMBOL_22_1 = 22, /* $@1 */ YYSYMBOL_range = 23, /* range */ YYSYMBOL_alternatives = 24, /* alternatives */ YYSYMBOL_byte = 25 /* byte */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; #ifdef short # undef short #endif /* On compilers that do not define __PTRDIFF_MAX__ etc., make sure and (if available) are included so that the code can choose integer types of a good width. */ #ifndef __PTRDIFF_MAX__ # include /* INFRINGES ON USER NAME SPACE */ # if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YY_STDINT_H # endif #endif /* Narrow types that promote to a signed type and that can represent a signed or unsigned integer of at least N bits. In tables they can save space and decrease cache pressure. Promoting to a signed type helps avoid bugs in integer arithmetic. */ #ifdef __INT_LEAST8_MAX__ typedef __INT_LEAST8_TYPE__ yytype_int8; #elif defined YY_STDINT_H typedef int_least8_t yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef __INT_LEAST16_MAX__ typedef __INT_LEAST16_TYPE__ yytype_int16; #elif defined YY_STDINT_H typedef int_least16_t yytype_int16; #else typedef short yytype_int16; #endif /* Work around bug in HP-UX 11.23, which defines these macros incorrectly for preprocessor constants. This workaround can likely be removed in 2023, as HPE has promised support for HP-UX 11.23 (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of . */ #ifdef __hpux # undef UINT_LEAST8_MAX # undef UINT_LEAST16_MAX # define UINT_LEAST8_MAX 255 # define UINT_LEAST16_MAX 65535 #endif #if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ typedef __UINT_LEAST8_TYPE__ yytype_uint8; #elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ && UINT_LEAST8_MAX <= INT_MAX) typedef uint_least8_t yytype_uint8; #elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX typedef unsigned char yytype_uint8; #else typedef short yytype_uint8; #endif #if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ typedef __UINT_LEAST16_TYPE__ yytype_uint16; #elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ && UINT_LEAST16_MAX <= INT_MAX) typedef uint_least16_t yytype_uint16; #elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX typedef unsigned short yytype_uint16; #else typedef int yytype_uint16; #endif #ifndef YYPTRDIFF_T # if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ # define YYPTRDIFF_T __PTRDIFF_TYPE__ # define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ # elif defined PTRDIFF_MAX # ifndef ptrdiff_t # include /* INFRINGES ON USER NAME SPACE */ # endif # define YYPTRDIFF_T ptrdiff_t # define YYPTRDIFF_MAXIMUM PTRDIFF_MAX # else # define YYPTRDIFF_T long # define YYPTRDIFF_MAXIMUM LONG_MAX # endif #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned # endif #endif #define YYSIZE_MAXIMUM \ YY_CAST (YYPTRDIFF_T, \ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ ? YYPTRDIFF_MAXIMUM \ : YY_CAST (YYSIZE_T, -1))) #define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) /* Stored state numbers (used for stacks). */ typedef yytype_int8 yy_state_t; /* State numbers in computations. */ typedef int yy_state_fast_t; #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE_PURE # if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) # else # define YY_ATTRIBUTE_PURE # endif #endif #ifndef YY_ATTRIBUTE_UNUSED # if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) # else # define YY_ATTRIBUTE_UNUSED # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YY_USE(E) ((void) (E)) #else # define YY_USE(E) /* empty */ #endif /* Suppress an incorrect diagnostic about yylval being uninitialized. */ #if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ # if __GNUC__ * 100 + __GNUC_MINOR__ < 407 # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") # else # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # endif # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ # define YY_IGNORE_USELESS_CAST_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") # define YY_IGNORE_USELESS_CAST_END \ _Pragma ("GCC diagnostic pop") #endif #ifndef YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_END #endif #define YY_ASSERT(E) ((void) (0 && (E))) #if !defined yyoverflow /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* !defined yyoverflow */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yy_state_t yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYPTRDIFF_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / YYSIZEOF (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYPTRDIFF_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 11 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 35 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 16 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 10 /* YYNRULES -- Number of rules. */ #define YYNRULES 22 /* YYNSTATES -- Number of states. */ #define YYNSTATES 34 /* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK 262 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM as returned by yylex, with out-of-bounds checking. */ #define YYTRANSLATE(YYX) \ (0 <= (YYX) && (YYX) <= YYMAXUTOK \ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ : YYSYMBOL_YYUNDEF) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex. */ static const yytype_int8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 11, 2, 2, 2, 14, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, 2, 13, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 8, 15, 9, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { 0, 107, 107, 116, 120, 132, 143, 152, 161, 165, 174, 179, 178, 191, 227, 259, 281, 301, 305, 322, 331, 340, 363 }; #endif /** Accessing symbol of state STATE. */ #define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) #if YYDEBUG || 0 /* The user-facing name of the symbol whose (internal) number is YYSYMBOL. No bounds checking. */ static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "\"end of file\"", "error", "\"invalid token\"", "_BYTE_", "_MASKED_BYTE_", "_NOT_BYTE_", "_MASKED_NOT_BYTE_", "_NUMBER_", "'{'", "'}'", "'('", "')'", "'['", "']'", "'-'", "'|'", "$accept", "hex_string", "tokens", "token_sequence", "token_or_range", "token", "$@1", "range", "alternatives", "byte", YY_NULLPTR }; static const char * yysymbol_name (yysymbol_kind_t yysymbol) { return yytname[yysymbol]; } #endif #define YYPACT_NINF (-13) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) #define YYTABLE_NINF (-6) #define yytable_value_is_error(Yyn) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int8 yypact[] = { 1, 12, 24, -13, -13, -13, -13, -13, 3, -2, -13, -13, 12, -13, -1, -2, -13, -4, -13, -13, 16, 19, 15, -13, 10, -13, 12, -13, 13, -13, -13, 17, -13, -13 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_int8 yydefact[] = { 0, 0, 0, 19, 21, 20, 22, 11, 0, 3, 10, 1, 0, 2, 0, 0, 6, 8, 9, 17, 0, 0, 0, 7, 8, 12, 0, 13, 0, 16, 18, 0, 15, 14 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -13, -13, -12, -13, 20, 14, -13, -13, -13, -13 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { 0, 2, 8, 15, 16, 9, 12, 18, 20, 10 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int8 yytable[] = { 19, 3, 4, 5, 6, -4, 21, -4, 7, 1, 14, -4, 13, 22, 30, 3, 4, 5, 6, -5, 31, -5, 7, 17, 11, -5, 32, 25, 29, 24, 33, 26, 27, 28, 0, 23 }; static const yytype_int8 yycheck[] = { 12, 3, 4, 5, 6, 9, 7, 11, 10, 8, 12, 15, 9, 14, 26, 3, 4, 5, 6, 9, 7, 11, 10, 9, 0, 15, 13, 11, 13, 15, 13, 15, 13, 14, -1, 15 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of state STATE-NUM. */ static const yytype_int8 yystos[] = { 0, 8, 17, 3, 4, 5, 6, 10, 18, 21, 25, 0, 22, 9, 12, 19, 20, 21, 23, 18, 24, 7, 14, 20, 21, 11, 15, 13, 14, 13, 18, 7, 13, 13 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_int8 yyr1[] = { 0, 16, 17, 18, 18, 18, 19, 19, 20, 20, 21, 22, 21, 23, 23, 23, 23, 24, 24, 25, 25, 25, 25 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 3, 1, 2, 3, 1, 2, 1, 1, 1, 0, 4, 3, 5, 4, 3, 1, 3, 1, 1, 1, 1 }; enum { YYENOMEM = -2 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYNOMEM goto yyexhaustedlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (yyscanner, lex_env, YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Backward compatibility with an undocumented macro. Use YYerror or YYUNDEF. */ #define YYERRCODE YYUNDEF /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Kind, Value, yyscanner, lex_env); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*-----------------------------------. | Print this symbol's value on YYO. | `-----------------------------------*/ static void yy_symbol_value_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, void *yyscanner, HEX_LEX_ENVIRONMENT *lex_env) { FILE *yyoutput = yyo; YY_USE (yyoutput); YY_USE (yyscanner); YY_USE (lex_env); if (!yyvaluep) return; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /*---------------------------. | Print this symbol on YYO. | `---------------------------*/ static void yy_symbol_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, void *yyscanner, HEX_LEX_ENVIRONMENT *lex_env) { YYFPRINTF (yyo, "%s %s (", yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); yy_symbol_value_print (yyo, yykind, yyvaluep, yyscanner, lex_env); YYFPRINTF (yyo, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, int yyrule, void *yyscanner, HEX_LEX_ENVIRONMENT *lex_env) { int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), &yyvsp[(yyi + 1) - (yynrhs)], yyscanner, lex_env); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, Rule, yyscanner, lex_env); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) ((void) 0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, yysymbol_kind_t yykind, YYSTYPE *yyvaluep, void *yyscanner, HEX_LEX_ENVIRONMENT *lex_env) { YY_USE (yyvaluep); YY_USE (yyscanner); YY_USE (lex_env); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN switch (yykind) { case YYSYMBOL_tokens: /* tokens */ #line 96 "hex_grammar.y" { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } #line 945 "hex_grammar.c" break; case YYSYMBOL_token_sequence: /* token_sequence */ #line 97 "hex_grammar.y" { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } #line 951 "hex_grammar.c" break; case YYSYMBOL_token_or_range: /* token_or_range */ #line 98 "hex_grammar.y" { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } #line 957 "hex_grammar.c" break; case YYSYMBOL_token: /* token */ #line 99 "hex_grammar.y" { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } #line 963 "hex_grammar.c" break; case YYSYMBOL_range: /* range */ #line 102 "hex_grammar.y" { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } #line 969 "hex_grammar.c" break; case YYSYMBOL_alternatives: /* alternatives */ #line 101 "hex_grammar.y" { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } #line 975 "hex_grammar.c" break; case YYSYMBOL_byte: /* byte */ #line 100 "hex_grammar.y" { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } #line 981 "hex_grammar.c" break; default: break; } YY_IGNORE_MAYBE_UNINITIALIZED_END } /*----------. | yyparse. | `----------*/ int yyparse (void *yyscanner, HEX_LEX_ENVIRONMENT *lex_env) { /* Lookahead token kind. */ int yychar; /* The semantic value of the lookahead symbol. */ /* Default value used for initialization, for pacifying older GCCs or non-GCC compilers. */ YY_INITIAL_VALUE (static YYSTYPE yyval_default;) YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); /* Number of syntax errors so far. */ int yynerrs = 0; yy_state_fast_t yystate = 0; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus = 0; /* Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* Their size. */ YYPTRDIFF_T yystacksize = YYINITDEPTH; /* The state stack: array, bottom, top. */ yy_state_t yyssa[YYINITDEPTH]; yy_state_t *yyss = yyssa; yy_state_t *yyssp = yyss; /* The semantic value stack: array, bottom, top. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; YYSTYPE *yyvsp = yyvs; int yyn; /* The return value of yyparse. */ int yyresult; /* Lookahead symbol kind. */ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; YYDPRINTF ((stderr, "Starting parse\n")); yychar = YYEMPTY; /* Cause a token to be read. */ goto yysetstate; /*------------------------------------------------------------. | yynewstate -- push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; /*--------------------------------------------------------------------. | yysetstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: YYDPRINTF ((stderr, "Entering state %d\n", yystate)); YY_ASSERT (0 <= yystate && yystate < YYNSTATES); YY_IGNORE_USELESS_CAST_BEGIN *yyssp = YY_CAST (yy_state_t, yystate); YY_IGNORE_USELESS_CAST_END YY_STACK_PRINT (yyss, yyssp); if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE YYNOMEM; #else { /* Get the current used size of the three stacks, in elements. */ YYPTRDIFF_T yysize = yyssp - yyss + 1; # if defined yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ yy_state_t *yyss1 = yyss; YYSTYPE *yyvs1 = yyvs; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * YYSIZEOF (*yyssp), &yyvs1, yysize * YYSIZEOF (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } # else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) YYNOMEM; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yy_state_t *yyss1 = yyss; union yyalloc *yyptr = YY_CAST (union yyalloc *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) YYNOMEM; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YY_IGNORE_USELESS_CAST_BEGIN YYDPRINTF ((stderr, "Stack size increased to %ld\n", YY_CAST (long, yystacksize))); YY_IGNORE_USELESS_CAST_END if (yyss + yystacksize - 1 <= yyssp) YYABORT; } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token\n")); yychar = yylex (&yylval, yyscanner, lex_env); } if (yychar <= YYEOF) { yychar = YYEOF; yytoken = YYSYMBOL_YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else if (yychar == YYerror) { /* The scanner already issued an error message, process directly to error recovery. But do not keep the error token as lookahead, it is too special and may lead us to an endless loop in error recovery. */ yychar = YYUNDEF; yytoken = YYSYMBOL_YYerror; goto yyerrlab1; } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Discard the shifted token. */ yychar = YYEMPTY; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 2: /* hex_string: '{' tokens '}' */ #line 108 "hex_grammar.y" { RE_AST* re_ast = yyget_extra(yyscanner); re_ast->root_node = (yyvsp[-1].re_node); } #line 1260 "hex_grammar.c" break; case 3: /* tokens: token */ #line 117 "hex_grammar.y" { (yyval.re_node) = (yyvsp[0].re_node); } #line 1268 "hex_grammar.c" break; case 4: /* tokens: token token */ #line 121 "hex_grammar.y" { (yyval.re_node) = yr_re_node_create(RE_NODE_CONCAT); destroy_node_if((yyval.re_node) == NULL, (yyvsp[-1].re_node)); destroy_node_if((yyval.re_node) == NULL, (yyvsp[0].re_node)); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child((yyval.re_node), (yyvsp[-1].re_node)); yr_re_node_append_child((yyval.re_node), (yyvsp[0].re_node)); } #line 1284 "hex_grammar.c" break; case 5: /* tokens: token token_sequence token */ #line 133 "hex_grammar.y" { yr_re_node_append_child((yyvsp[-1].re_node), (yyvsp[0].re_node)); yr_re_node_prepend_child((yyvsp[-1].re_node), (yyvsp[-2].re_node)); (yyval.re_node) = (yyvsp[-1].re_node); } #line 1295 "hex_grammar.c" break; case 6: /* token_sequence: token_or_range */ #line 144 "hex_grammar.y" { (yyval.re_node) = yr_re_node_create(RE_NODE_CONCAT); destroy_node_if((yyval.re_node) == NULL, (yyvsp[0].re_node)); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child((yyval.re_node), (yyvsp[0].re_node)); } #line 1308 "hex_grammar.c" break; case 7: /* token_sequence: token_sequence token_or_range */ #line 153 "hex_grammar.y" { yr_re_node_append_child((yyvsp[-1].re_node), (yyvsp[0].re_node)); (yyval.re_node) = (yyvsp[-1].re_node); } #line 1317 "hex_grammar.c" break; case 8: /* token_or_range: token */ #line 162 "hex_grammar.y" { (yyval.re_node) = (yyvsp[0].re_node); } #line 1325 "hex_grammar.c" break; case 9: /* token_or_range: range */ #line 166 "hex_grammar.y" { (yyval.re_node) = (yyvsp[0].re_node); (yyval.re_node)->greedy = false; } #line 1334 "hex_grammar.c" break; case 10: /* token: byte */ #line 175 "hex_grammar.y" { (yyval.re_node) = (yyvsp[0].re_node); } #line 1342 "hex_grammar.c" break; case 11: /* $@1: %empty */ #line 179 "hex_grammar.y" { lex_env->inside_or++; } #line 1350 "hex_grammar.c" break; case 12: /* token: '(' $@1 alternatives ')' */ #line 183 "hex_grammar.y" { (yyval.re_node) = (yyvsp[-1].re_node); lex_env->inside_or--; } #line 1359 "hex_grammar.c" break; case 13: /* range: '[' _NUMBER_ ']' */ #line 192 "hex_grammar.y" { if ((yyvsp[-1].integer) <= 0) { yyerror(yyscanner, lex_env, "invalid jump length"); YYABORT; } if (lex_env->inside_or && (yyvsp[-1].integer) > YR_STRING_CHAINING_THRESHOLD) { yyerror(yyscanner, lex_env, "jumps over " STR(YR_STRING_CHAINING_THRESHOLD) " not allowed inside alternation (|)"); YYABORT; } // A jump of one is equivalent to ?? if ((yyvsp[-1].integer) == 1) { (yyval.re_node) = yr_re_node_create(RE_NODE_MASKED_LITERAL); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); (yyval.re_node)->value = 0x00; (yyval.re_node)->mask = 0x00; } else { (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE_ANY); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); (yyval.re_node)->start = (int) (yyvsp[-1].integer); (yyval.re_node)->end = (int) (yyvsp[-1].integer); } } #line 1399 "hex_grammar.c" break; case 14: /* range: '[' _NUMBER_ '-' _NUMBER_ ']' */ #line 228 "hex_grammar.y" { if (lex_env->inside_or && ((yyvsp[-3].integer) > YR_STRING_CHAINING_THRESHOLD || (yyvsp[-1].integer) > YR_STRING_CHAINING_THRESHOLD) ) { yyerror(yyscanner, lex_env, "jumps over " STR(YR_STRING_CHAINING_THRESHOLD) " not allowed inside alternation (|)"); YYABORT; } if ((yyvsp[-3].integer) < 0 || (yyvsp[-1].integer) < 0) { yyerror(yyscanner, lex_env, "invalid negative jump length"); YYABORT; } if ((yyvsp[-3].integer) > (yyvsp[-1].integer)) { yyerror(yyscanner, lex_env, "invalid jump range"); YYABORT; } (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE_ANY); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); (yyval.re_node)->start = (int) (yyvsp[-3].integer); (yyval.re_node)->end = (int) (yyvsp[-1].integer); } #line 1435 "hex_grammar.c" break; case 15: /* range: '[' _NUMBER_ '-' ']' */ #line 260 "hex_grammar.y" { if (lex_env->inside_or) { yyerror(yyscanner, lex_env, "unbounded jumps not allowed inside alternation (|)"); YYABORT; } if ((yyvsp[-2].integer) < 0) { yyerror(yyscanner, lex_env, "invalid negative jump length"); YYABORT; } (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE_ANY); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); (yyval.re_node)->start = (int) (yyvsp[-2].integer); (yyval.re_node)->end = INT_MAX; } #line 1461 "hex_grammar.c" break; case 16: /* range: '[' '-' ']' */ #line 282 "hex_grammar.y" { if (lex_env->inside_or) { yyerror(yyscanner, lex_env, "unbounded jumps not allowed inside alternation (|)"); YYABORT; } (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE_ANY); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); (yyval.re_node)->start = 0; (yyval.re_node)->end = INT_MAX; } #line 1481 "hex_grammar.c" break; case 17: /* alternatives: tokens */ #line 302 "hex_grammar.y" { (yyval.re_node) = (yyvsp[0].re_node); } #line 1489 "hex_grammar.c" break; case 18: /* alternatives: alternatives '|' tokens */ #line 306 "hex_grammar.y" { mark_as_not_fast_regexp(); (yyval.re_node) = yr_re_node_create(RE_NODE_ALT); destroy_node_if((yyval.re_node) == NULL, (yyvsp[-2].re_node)); destroy_node_if((yyval.re_node) == NULL, (yyvsp[0].re_node)); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child((yyval.re_node), (yyvsp[-2].re_node)); yr_re_node_append_child((yyval.re_node), (yyvsp[0].re_node)); } #line 1507 "hex_grammar.c" break; case 19: /* byte: _BYTE_ */ #line 323 "hex_grammar.y" { (yyval.re_node) = yr_re_node_create(RE_NODE_LITERAL); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); (yyval.re_node)->value = (int) (yyvsp[0].integer); (yyval.re_node)->mask = 0xFF; } #line 1520 "hex_grammar.c" break; case 20: /* byte: _NOT_BYTE_ */ #line 332 "hex_grammar.y" { (yyval.re_node) = yr_re_node_create(RE_NODE_NOT_LITERAL); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); (yyval.re_node)->value = (int) (yyvsp[0].integer); (yyval.re_node)->mask = 0xFF; } #line 1533 "hex_grammar.c" break; case 21: /* byte: _MASKED_BYTE_ */ #line 341 "hex_grammar.y" { uint8_t mask = (uint8_t) ((yyvsp[0].integer) >> 8); if (mask == 0x00) { (yyval.re_node) = yr_re_node_create(RE_NODE_ANY); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); (yyval.re_node)->value = 0x00; (yyval.re_node)->mask = 0x00; } else { (yyval.re_node) = yr_re_node_create(RE_NODE_MASKED_LITERAL); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); (yyval.re_node)->value = (yyvsp[0].integer) & 0xFF; (yyval.re_node)->mask = mask; } } #line 1560 "hex_grammar.c" break; case 22: /* byte: _MASKED_NOT_BYTE_ */ #line 364 "hex_grammar.y" { uint8_t mask = (uint8_t) ((yyvsp[0].integer) >> 8); (yyval.re_node) = yr_re_node_create(RE_NODE_MASKED_NOT_LITERAL); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); (yyval.re_node)->value = (yyvsp[0].integer) & 0xFF; (yyval.re_node)->mask = mask; } #line 1575 "hex_grammar.c" break; #line 1579 "hex_grammar.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; *++yyvsp = yyval; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ { const int yylhs = yyr1[yyn] - YYNTOKENS; const int yyi = yypgoto[yylhs] + *yyssp; yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp ? yytable[yyi] : yydefgoto[yylhs]); } goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; yyerror (yyscanner, lex_env, YY_("syntax error")); } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval, yyscanner, lex_env); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (0) YYERROR; ++yynerrs; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ /* Pop stack until we find a state that shifts the error token. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYSYMBOL_YYerror; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", YY_ACCESSING_SYMBOL (yystate), yyvsp, yyscanner, lex_env); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturnlab; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturnlab; /*-----------------------------------------------------------. | yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | `-----------------------------------------------------------*/ yyexhaustedlab: yyerror (yyscanner, lex_env, YY_("memory exhausted")); yyresult = 2; goto yyreturnlab; /*----------------------------------------------------------. | yyreturnlab -- parsing is finished, clean up and return. | `----------------------------------------------------------*/ yyreturnlab: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval, yyscanner, lex_env); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yyscanner, lex_env); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif return yyresult; } #line 376 "hex_grammar.y" yara-4.5.3/libyara/hex_grammar.h000066400000000000000000000060661501365277300165660ustar00rootroot00000000000000/* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison interface for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. 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 . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ #ifndef YY_HEX_YY_HEX_GRAMMAR_H_INCLUDED # define YY_HEX_YY_HEX_GRAMMAR_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int hex_yydebug; #endif /* Token kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, YYEOF = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ _BYTE_ = 258, /* _BYTE_ */ _MASKED_BYTE_ = 259, /* _MASKED_BYTE_ */ _NOT_BYTE_ = 260, /* _NOT_BYTE_ */ _MASKED_NOT_BYTE_ = 261, /* _MASKED_NOT_BYTE_ */ _NUMBER_ = 262 /* _NUMBER_ */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Token kinds. */ #define YYEMPTY -2 #define YYEOF 0 #define YYerror 256 #define YYUNDEF 257 #define _BYTE_ 258 #define _MASKED_BYTE_ 259 #define _NOT_BYTE_ 260 #define _MASKED_NOT_BYTE_ 261 #define _NUMBER_ 262 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 78 "hex_grammar.y" int64_t integer; RE_NODE *re_node; #line 86 "hex_grammar.h" }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif int hex_yyparse (void *yyscanner, HEX_LEX_ENVIRONMENT *lex_env); #endif /* !YY_HEX_YY_HEX_GRAMMAR_H_INCLUDED */ yara-4.5.3/libyara/hex_grammar.y000066400000000000000000000207401501365277300166020ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ %{ #include #include #include #include #include #include #include #include #define STR_EXPAND(tok) #tok #define STR(tok) STR_EXPAND(tok) #define YYERROR_VERBOSE #define YYMALLOC yr_malloc #define YYFREE yr_free #define mark_as_not_fast_regexp() \ ((RE_AST*) yyget_extra(yyscanner))->flags &= ~RE_FLAGS_FAST_REGEXP #define fail_if(x, error) \ if (x) \ { \ lex_env->last_error = error; \ YYABORT; \ } \ #define destroy_node_if(x, node) \ if (x) \ { \ yr_re_node_destroy(node); \ } \ %} %name-prefix "hex_yy" %pure-parser %parse-param {void *yyscanner} %parse-param {HEX_LEX_ENVIRONMENT *lex_env} %lex-param {yyscan_t yyscanner} %lex-param {HEX_LEX_ENVIRONMENT *lex_env} %union { int64_t integer; RE_NODE *re_node; } %token _BYTE_ %token _MASKED_BYTE_ %token _NOT_BYTE_ %token _MASKED_NOT_BYTE_ %token _NUMBER_ %type tokens %type token_sequence %type token_or_range %type token byte %type alternatives %type range %destructor { yr_re_node_destroy($$); $$ = NULL; } tokens %destructor { yr_re_node_destroy($$); $$ = NULL; } token_sequence %destructor { yr_re_node_destroy($$); $$ = NULL; } token_or_range %destructor { yr_re_node_destroy($$); $$ = NULL; } token %destructor { yr_re_node_destroy($$); $$ = NULL; } byte %destructor { yr_re_node_destroy($$); $$ = NULL; } alternatives %destructor { yr_re_node_destroy($$); $$ = NULL; } range %% hex_string : '{' tokens '}' { RE_AST* re_ast = yyget_extra(yyscanner); re_ast->root_node = $2; } ; tokens : token { $$ = $1; } | token token { $$ = yr_re_node_create(RE_NODE_CONCAT); destroy_node_if($$ == NULL, $1); destroy_node_if($$ == NULL, $2); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child($$, $1); yr_re_node_append_child($$, $2); } | token token_sequence token { yr_re_node_append_child($2, $3); yr_re_node_prepend_child($2, $1); $$ = $2; } ; token_sequence : token_or_range { $$ = yr_re_node_create(RE_NODE_CONCAT); destroy_node_if($$ == NULL, $1); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child($$, $1); } | token_sequence token_or_range { yr_re_node_append_child($1, $2); $$ = $1; } ; token_or_range : token { $$ = $1; } | range { $$ = $1; $$->greedy = false; } ; token : byte { $$ = $1; } | '(' { lex_env->inside_or++; } alternatives ')' { $$ = $3; lex_env->inside_or--; } ; range : '[' _NUMBER_ ']' { if ($2 <= 0) { yyerror(yyscanner, lex_env, "invalid jump length"); YYABORT; } if (lex_env->inside_or && $2 > YR_STRING_CHAINING_THRESHOLD) { yyerror(yyscanner, lex_env, "jumps over " STR(YR_STRING_CHAINING_THRESHOLD) " not allowed inside alternation (|)"); YYABORT; } // A jump of one is equivalent to ?? if ($2 == 1) { $$ = yr_re_node_create(RE_NODE_MASKED_LITERAL); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); $$->value = 0x00; $$->mask = 0x00; } else { $$ = yr_re_node_create(RE_NODE_RANGE_ANY); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); $$->start = (int) $2; $$->end = (int) $2; } } | '[' _NUMBER_ '-' _NUMBER_ ']' { if (lex_env->inside_or && ($2 > YR_STRING_CHAINING_THRESHOLD || $4 > YR_STRING_CHAINING_THRESHOLD) ) { yyerror(yyscanner, lex_env, "jumps over " STR(YR_STRING_CHAINING_THRESHOLD) " not allowed inside alternation (|)"); YYABORT; } if ($2 < 0 || $4 < 0) { yyerror(yyscanner, lex_env, "invalid negative jump length"); YYABORT; } if ($2 > $4) { yyerror(yyscanner, lex_env, "invalid jump range"); YYABORT; } $$ = yr_re_node_create(RE_NODE_RANGE_ANY); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); $$->start = (int) $2; $$->end = (int) $4; } | '[' _NUMBER_ '-' ']' { if (lex_env->inside_or) { yyerror(yyscanner, lex_env, "unbounded jumps not allowed inside alternation (|)"); YYABORT; } if ($2 < 0) { yyerror(yyscanner, lex_env, "invalid negative jump length"); YYABORT; } $$ = yr_re_node_create(RE_NODE_RANGE_ANY); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); $$->start = (int) $2; $$->end = INT_MAX; } | '[' '-' ']' { if (lex_env->inside_or) { yyerror(yyscanner, lex_env, "unbounded jumps not allowed inside alternation (|)"); YYABORT; } $$ = yr_re_node_create(RE_NODE_RANGE_ANY); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); $$->start = 0; $$->end = INT_MAX; } ; alternatives : tokens { $$ = $1; } | alternatives '|' tokens { mark_as_not_fast_regexp(); $$ = yr_re_node_create(RE_NODE_ALT); destroy_node_if($$ == NULL, $1); destroy_node_if($$ == NULL, $3); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child($$, $1); yr_re_node_append_child($$, $3); } ; byte : _BYTE_ { $$ = yr_re_node_create(RE_NODE_LITERAL); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); $$->value = (int) $1; $$->mask = 0xFF; } | _NOT_BYTE_ { $$ = yr_re_node_create(RE_NODE_NOT_LITERAL); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); $$->value = (int) $1; $$->mask = 0xFF; } | _MASKED_BYTE_ { uint8_t mask = (uint8_t) ($1 >> 8); if (mask == 0x00) { $$ = yr_re_node_create(RE_NODE_ANY); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); $$->value = 0x00; $$->mask = 0x00; } else { $$ = yr_re_node_create(RE_NODE_MASKED_LITERAL); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); $$->value = $1 & 0xFF; $$->mask = mask; } } | _MASKED_NOT_BYTE_ { uint8_t mask = (uint8_t) ($1 >> 8); $$ = yr_re_node_create(RE_NODE_MASKED_NOT_LITERAL); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); $$->value = $1 & 0xFF; $$->mask = mask; } ; %% yara-4.5.3/libyara/hex_lexer.c000066400000000000000000002046621501365277300162540ustar00rootroot00000000000000#line 1 "libyara/hex_lexer.c" #line 3 "libyara/hex_lexer.c" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 6 #define YY_FLEX_SUBMINOR_VERSION 4 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif #ifdef yy_create_buffer #define hex_yy_create_buffer_ALREADY_DEFINED #else #define yy_create_buffer hex_yy_create_buffer #endif #ifdef yy_delete_buffer #define hex_yy_delete_buffer_ALREADY_DEFINED #else #define yy_delete_buffer hex_yy_delete_buffer #endif #ifdef yy_scan_buffer #define hex_yy_scan_buffer_ALREADY_DEFINED #else #define yy_scan_buffer hex_yy_scan_buffer #endif #ifdef yy_scan_string #define hex_yy_scan_string_ALREADY_DEFINED #else #define yy_scan_string hex_yy_scan_string #endif #ifdef yy_scan_bytes #define hex_yy_scan_bytes_ALREADY_DEFINED #else #define yy_scan_bytes hex_yy_scan_bytes #endif #ifdef yy_init_buffer #define hex_yy_init_buffer_ALREADY_DEFINED #else #define yy_init_buffer hex_yy_init_buffer #endif #ifdef yy_flush_buffer #define hex_yy_flush_buffer_ALREADY_DEFINED #else #define yy_flush_buffer hex_yy_flush_buffer #endif #ifdef yy_load_buffer_state #define hex_yy_load_buffer_state_ALREADY_DEFINED #else #define yy_load_buffer_state hex_yy_load_buffer_state #endif #ifdef yy_switch_to_buffer #define hex_yy_switch_to_buffer_ALREADY_DEFINED #else #define yy_switch_to_buffer hex_yy_switch_to_buffer #endif #ifdef yypush_buffer_state #define hex_yypush_buffer_state_ALREADY_DEFINED #else #define yypush_buffer_state hex_yypush_buffer_state #endif #ifdef yypop_buffer_state #define hex_yypop_buffer_state_ALREADY_DEFINED #else #define yypop_buffer_state hex_yypop_buffer_state #endif #ifdef yyensure_buffer_stack #define hex_yyensure_buffer_stack_ALREADY_DEFINED #else #define yyensure_buffer_stack hex_yyensure_buffer_stack #endif #ifdef yylex #define hex_yylex_ALREADY_DEFINED #else #define yylex hex_yylex #endif #ifdef yyrestart #define hex_yyrestart_ALREADY_DEFINED #else #define yyrestart hex_yyrestart #endif #ifdef yylex_init #define hex_yylex_init_ALREADY_DEFINED #else #define yylex_init hex_yylex_init #endif #ifdef yylex_init_extra #define hex_yylex_init_extra_ALREADY_DEFINED #else #define yylex_init_extra hex_yylex_init_extra #endif #ifdef yylex_destroy #define hex_yylex_destroy_ALREADY_DEFINED #else #define yylex_destroy hex_yylex_destroy #endif #ifdef yyget_debug #define hex_yyget_debug_ALREADY_DEFINED #else #define yyget_debug hex_yyget_debug #endif #ifdef yyset_debug #define hex_yyset_debug_ALREADY_DEFINED #else #define yyset_debug hex_yyset_debug #endif #ifdef yyget_extra #define hex_yyget_extra_ALREADY_DEFINED #else #define yyget_extra hex_yyget_extra #endif #ifdef yyset_extra #define hex_yyset_extra_ALREADY_DEFINED #else #define yyset_extra hex_yyset_extra #endif #ifdef yyget_in #define hex_yyget_in_ALREADY_DEFINED #else #define yyget_in hex_yyget_in #endif #ifdef yyset_in #define hex_yyset_in_ALREADY_DEFINED #else #define yyset_in hex_yyset_in #endif #ifdef yyget_out #define hex_yyget_out_ALREADY_DEFINED #else #define yyget_out hex_yyget_out #endif #ifdef yyset_out #define hex_yyset_out_ALREADY_DEFINED #else #define yyset_out hex_yyset_out #endif #ifdef yyget_leng #define hex_yyget_leng_ALREADY_DEFINED #else #define yyget_leng hex_yyget_leng #endif #ifdef yyget_text #define hex_yyget_text_ALREADY_DEFINED #else #define yyget_text hex_yyget_text #endif #ifdef yyget_lineno #define hex_yyget_lineno_ALREADY_DEFINED #else #define yyget_lineno hex_yyget_lineno #endif #ifdef yyset_lineno #define hex_yyset_lineno_ALREADY_DEFINED #else #define yyset_lineno hex_yyset_lineno #endif #ifdef yyget_column #define hex_yyget_column_ALREADY_DEFINED #else #define yyget_column hex_yyget_column #endif #ifdef yyset_column #define hex_yyset_column_ALREADY_DEFINED #else #define yyset_column hex_yyset_column #endif #ifdef yywrap #define hex_yywrap_ALREADY_DEFINED #else #define yywrap hex_yywrap #endif #ifdef yyget_lval #define hex_yyget_lval_ALREADY_DEFINED #else #define yyget_lval hex_yyget_lval #endif #ifdef yyset_lval #define hex_yyset_lval_ALREADY_DEFINED #else #define yyset_lval hex_yyset_lval #endif #ifdef yyalloc #define hex_yyalloc_ALREADY_DEFINED #else #define yyalloc hex_yyalloc #endif #ifdef yyrealloc #define hex_yyrealloc_ALREADY_DEFINED #else #define yyrealloc hex_yyrealloc #endif #ifdef yyfree #define hex_yyfree_ALREADY_DEFINED #else #define yyfree hex_yyfree #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #ifndef SIZE_MAX #define SIZE_MAX (~(size_t)0) #endif #endif /* ! C99 */ #endif /* ! FLEXINT_H */ /* begin standard C++ headers. */ /* TODO: this is always defined, so inline it */ #define yyconst const #if defined(__GNUC__) && __GNUC__ >= 3 #define yynoreturn __attribute__((__noreturn__)) #else #define yynoreturn #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an * integer in range [0..255] for use as an array index. */ #define YY_SC_TO_UI(c) ((YY_CHAR) (c)) /* An opaque pointer. */ #ifndef YY_TYPEDEF_YY_SCANNER_T #define YY_TYPEDEF_YY_SCANNER_T typedef void* yyscan_t; #endif /* For convenience, these vars (plus the bison vars far below) are macros in the reentrant scanner. */ #define yyin yyg->yyin_r #define yyout yyg->yyout_r #define yyextra yyg->yyextra_r #define yyleng yyg->yyleng_r #define yytext yyg->yytext_r #define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) #define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) #define yy_flex_debug yyg->yy_flex_debug_r /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN yyg->yy_start = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START ((yyg->yy_start - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart( yyin , yyscanner ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k. * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. * Ditto for the __ia64__ case accordingly. */ #define YY_BUF_SIZE 32768 #else #define YY_BUF_SIZE 16384 #endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires * access to the local variable yy_act. Since yyless() is a macro, it would break * existing scanners that call yyless() from OUTSIDE yylex. * One obvious solution it to make yy_act a global. I tried that, and saw * a 5% performance hit in a non-yylineno scanner, because yy_act is * normally declared as a register variable-- so it is not worth it. */ #define YY_LESS_LINENO(n) \ do { \ int yyl;\ for ( yyl = n; yyl < yyleng; ++yyl )\ if ( yytext[yyl] == '\n' )\ --yylineno;\ }while(0) #define YY_LINENO_REWIND_TO(dst) \ do {\ const char *p;\ for ( p = yy_cp-1; p >= (dst); --p)\ if ( *p == '\n' )\ --yylineno;\ }while(0) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = yyg->yy_hold_char; \ YY_RESTORE_YY_MORE_OFFSET \ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] void yyrestart ( FILE *input_file , yyscan_t yyscanner ); void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); void yypop_buffer_state ( yyscan_t yyscanner ); static void yyensure_buffer_stack ( yyscan_t yyscanner ); static void yy_load_buffer_state ( yyscan_t yyscanner ); static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); #define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); void *yyalloc ( yy_size_t , yyscan_t yyscanner ); void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); void yyfree ( void * , yyscan_t yyscanner ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (yyscanner); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (yyscanner); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ #define hex_yywrap(yyscanner) (/*CONSTCOND*/1) #define YY_SKIP_YYWRAP typedef flex_uint8_t YY_CHAR; typedef int yy_state_type; #define yytext_ptr yytext_r static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); static int yy_get_next_buffer ( yyscan_t yyscanner ); static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ yyg->yytext_ptr = yy_bp; \ yyleng = (int) (yy_cp - yy_bp); \ yyg->yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; #define YY_NUM_RULES 23 #define YY_END_OF_BUFFER 24 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static const flex_int16_t yy_accept[40] = { 0, 0, 0, 0, 0, 0, 0, 24, 22, 20, 20, 21, 22, 8, 22, 10, 9, 13, 13, 19, 18, 18, 15, 16, 17, 11, 14, 1, 2, 4, 5, 0, 0, 12, 16, 14, 3, 6, 7, 0 } ; static const YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 4, 4, 5, 1, 1, 6, 1, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, 1, 1, 9, 1, 10, 10, 10, 10, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 11, 1, 12, 1, 1, 1, 10, 10, 10, 10, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static const YY_CHAR yy_meta[14] = { 0, 1, 1, 2, 1, 1, 1, 1, 3, 4, 3, 1, 1, 1 } ; static const flex_int16_t yy_base[48] = { 0, 0, 0, 28, 27, 12, 23, 30, 59, 59, 59, 59, 31, 19, 18, 59, 14, 59, 15, 59, 59, 59, 59, 13, 59, 59, 0, 59, 59, 59, 59, 10, 0, 59, 9, 0, 59, 59, 59, 59, 38, 42, 44, 46, 48, 52, 54, 13 } ; static const flex_int16_t yy_def[48] = { 0, 39, 1, 40, 40, 41, 41, 39, 39, 39, 39, 39, 39, 42, 43, 39, 44, 39, 39, 39, 39, 39, 39, 39, 39, 39, 45, 39, 39, 39, 39, 46, 47, 39, 39, 45, 39, 39, 39, 0, 39, 39, 39, 39, 39, 39, 39, 39 } ; static const flex_int16_t yy_nxt[73] = { 0, 8, 9, 10, 11, 8, 8, 12, 13, 14, 13, 15, 8, 16, 20, 21, 38, 34, 22, 37, 23, 34, 33, 32, 24, 20, 21, 30, 28, 22, 39, 23, 18, 18, 39, 24, 25, 39, 26, 17, 17, 17, 17, 19, 19, 19, 19, 27, 27, 29, 29, 31, 31, 35, 39, 35, 35, 36, 36, 7, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39 } ; static const flex_int16_t yy_chk[73] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 47, 34, 5, 31, 5, 23, 18, 16, 5, 6, 6, 14, 13, 6, 7, 6, 4, 3, 0, 6, 12, 0, 12, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 43, 43, 44, 44, 45, 0, 45, 45, 46, 46, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39 } ; /* Table of booleans, true if rule could match eol. */ static const flex_int32_t yy_rule_can_match_eol[24] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, }; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET #line 1 "libyara/hex_lexer.l" /* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Lexical analyzer for hex strings */ #line 33 "libyara/hex_lexer.l" /* Disable warnings for unused functions in this file. As we redefine YY_FATAL_ERROR macro to use our own function hex_yyfatal, the yy_fatal_error function generated by Flex is not actually used, causing a compiler warning. Flex doesn't offer any options to remove the yy_fatal_error function. When they include something like %option noyy_fatal_error as they do with noyywrap then we can remove this pragma. */ #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wunused-function" #endif #include #include #include #include #include #include #include #include #include #include "hex_grammar.h" #ifdef _WIN32 #define snprintf _snprintf #endif #define ERROR_IF(x, error) \ if (x) \ { \ RE_AST* re_ast = yyget_extra(yyscanner); \ re_ast->error_code = error; \ YYABORT; \ } \ #line 763 "libyara/hex_lexer.c" #define YY_NO_UNISTD_H 1 #define YY_NO_INPUT 1 #line 767 "libyara/hex_lexer.c" #define INITIAL 0 #define comment 1 #define range 2 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif /* Holds the entire state of the reentrant scanner. */ struct yyguts_t { /* User-defined. Not touched by flex. */ YY_EXTRA_TYPE yyextra_r; /* The rest are the same as the globals declared in the non-reentrant scanner. */ FILE *yyin_r, *yyout_r; size_t yy_buffer_stack_top; /**< index of top of stack. */ size_t yy_buffer_stack_max; /**< capacity of stack. */ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ char yy_hold_char; int yy_n_chars; int yyleng_r; char *yy_c_buf_p; int yy_init; int yy_start; int yy_did_buffer_switch_on_eof; int yy_start_stack_ptr; int yy_start_stack_depth; int *yy_start_stack; yy_state_type yy_last_accepting_state; char* yy_last_accepting_cpos; int yylineno_r; int yy_flex_debug_r; char *yytext_r; int yy_more_flag; int yy_more_len; YYSTYPE * yylval_r; }; /* end struct yyguts_t */ static int yy_init_globals ( yyscan_t yyscanner ); /* This must go here because YYSTYPE and YYLTYPE are included * from bison output in section 1.*/ # define yylval yyg->yylval_r int yylex_init (yyscan_t* scanner); int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy ( yyscan_t yyscanner ); int yyget_debug ( yyscan_t yyscanner ); void yyset_debug ( int debug_flag , yyscan_t yyscanner ); YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); FILE *yyget_in ( yyscan_t yyscanner ); void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); FILE *yyget_out ( yyscan_t yyscanner ); void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); int yyget_leng ( yyscan_t yyscanner ); char *yyget_text ( yyscan_t yyscanner ); int yyget_lineno ( yyscan_t yyscanner ); void yyset_lineno ( int _line_number , yyscan_t yyscanner ); int yyget_column ( yyscan_t yyscanner ); void yyset_column ( int _column_no , yyscan_t yyscanner ); YYSTYPE * yyget_lval ( yyscan_t yyscanner ); void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap ( yyscan_t yyscanner ); #else extern int yywrap ( yyscan_t yyscanner ); #endif #endif #ifndef YY_NO_UNPUT #endif #ifndef yytext_ptr static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen ( const char * , yyscan_t yyscanner); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput ( yyscan_t yyscanner ); #else static int input ( yyscan_t yyscanner ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k */ #define YY_READ_BUF_SIZE 16384 #else #define YY_READ_BUF_SIZE 8192 #endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ int n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex \ (YYSTYPE * yylval_param , yyscan_t yyscanner); #define YY_DECL int yylex \ (YYSTYPE * yylval_param , yyscan_t yyscanner) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { yy_state_type yy_current_state; char *yy_cp, *yy_bp; int yy_act; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yylval = yylval_param; if ( !yyg->yy_init ) { yyg->yy_init = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! yyg->yy_start ) yyg->yy_start = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (yyscanner); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); } yy_load_buffer_state( yyscanner ); } { #line 95 "libyara/hex_lexer.l" #line 1045 "libyara/hex_lexer.c" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { yy_cp = yyg->yy_c_buf_p; /* Support of yytext. */ *yy_cp = yyg->yy_hold_char; /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = yyg->yy_start; yy_match: do { YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 40 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } while ( yy_current_state != 39 ); yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; yy_find_action: yy_act = yy_accept[yy_current_state]; YY_DO_BEFORE_ACTION; if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) { int yyl; for ( yyl = 0; yyl < yyleng; ++yyl ) if ( yytext[yyl] == '\n' ) do{ yylineno++; yycolumn=0; }while(0) ; } do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = yyg->yy_hold_char; yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; goto yy_find_action; case 1: YY_RULE_SETUP #line 98 "libyara/hex_lexer.l" { yylval->integer = xtoi(yytext); return _BYTE_; } YY_BREAK case 2: YY_RULE_SETUP #line 104 "libyara/hex_lexer.l" { yytext[1] = '0'; // replace ? by 0 yylval->integer = xtoi(yytext) | 0xF000 ; return _MASKED_BYTE_; } YY_BREAK case 3: YY_RULE_SETUP #line 111 "libyara/hex_lexer.l" { yylval->integer = xtoi(&(yytext[1])); return _NOT_BYTE_; } YY_BREAK case 4: YY_RULE_SETUP #line 117 "libyara/hex_lexer.l" { yytext[0] = '0'; // replace ? by 0 yylval->integer = xtoi(yytext) | 0x0F00 ; return _MASKED_BYTE_; } YY_BREAK case 5: YY_RULE_SETUP #line 124 "libyara/hex_lexer.l" { yylval->integer = 0x0000; return _MASKED_BYTE_; } YY_BREAK case 6: YY_RULE_SETUP #line 130 "libyara/hex_lexer.l" { yytext[2] = '0'; // replace ? by 0 yylval->integer = xtoi(&(yytext[1])) | 0xF000 ; return _MASKED_NOT_BYTE_; } YY_BREAK case 7: YY_RULE_SETUP #line 137 "libyara/hex_lexer.l" { yytext[1] = '0'; // replace ? by 0 yylval->integer = xtoi(&(yytext[1])) | 0x0F00 ; return _MASKED_NOT_BYTE_; } YY_BREAK case 8: YY_RULE_SETUP #line 144 "libyara/hex_lexer.l" { yyerror(yyscanner, lex_env, "uneven number of digits in hex string"); yyterminate(); } YY_BREAK case 9: YY_RULE_SETUP #line 150 "libyara/hex_lexer.l" { yyerror(yyscanner, lex_env, "invalid not operator (~) in hex string"); yyterminate(); } YY_BREAK case 10: YY_RULE_SETUP #line 157 "libyara/hex_lexer.l" { BEGIN(range); return yytext[0]; } YY_BREAK case 11: YY_RULE_SETUP #line 163 "libyara/hex_lexer.l" { BEGIN(comment); } YY_BREAK case 12: YY_RULE_SETUP #line 168 "libyara/hex_lexer.l" { BEGIN(INITIAL); } YY_BREAK case 13: /* rule 13 can match eol */ YY_RULE_SETUP #line 173 "libyara/hex_lexer.l" // skip comments YY_BREAK case 14: YY_RULE_SETUP #line 175 "libyara/hex_lexer.l" // skip single-line comments YY_BREAK case 15: YY_RULE_SETUP #line 177 "libyara/hex_lexer.l" { return yytext[0]; } YY_BREAK case 16: YY_RULE_SETUP #line 182 "libyara/hex_lexer.l" { yylval->integer = atoi(yytext); return _NUMBER_; } YY_BREAK case 17: YY_RULE_SETUP #line 188 "libyara/hex_lexer.l" { BEGIN(INITIAL); return yytext[0]; } YY_BREAK case 18: /* rule 18 can match eol */ YY_RULE_SETUP #line 194 "libyara/hex_lexer.l" // skip whitespaces YY_BREAK case 19: YY_RULE_SETUP #line 196 "libyara/hex_lexer.l" { yyerror(yyscanner, lex_env, "invalid character in hex string jump"); yyterminate(); } YY_BREAK case 20: /* rule 20 can match eol */ YY_RULE_SETUP #line 202 "libyara/hex_lexer.l" // skip whitespaces YY_BREAK case 21: YY_RULE_SETUP #line 204 "libyara/hex_lexer.l" { // pass valid characters to the parser return yytext[0]; } YY_BREAK case 22: YY_RULE_SETUP #line 209 "libyara/hex_lexer.l" { // reject all other characters yyerror(yyscanner, lex_env, "invalid character in hex string"); yyterminate(); } YY_BREAK case 23: YY_RULE_SETUP #line 215 "libyara/hex_lexer.l" ECHO; YY_BREAK #line 1300 "libyara/hex_lexer.c" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(comment): case YY_STATE_EOF(range): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = yyg->yy_hold_char; YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) { /* This was really a NUL. */ yy_state_type yy_next_state; yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( yyscanner ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++yyg->yy_c_buf_p; yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; goto yy_find_action; } } else switch ( yy_get_next_buffer( yyscanner ) ) { case EOB_ACT_END_OF_FILE: { yyg->yy_did_buffer_switch_on_eof = 0; if ( yywrap( yyscanner ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( yyscanner ); yy_cp = yyg->yy_c_buf_p; yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: yyg->yy_c_buf_p = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; yy_current_state = yy_get_previous_state( yyscanner ); yy_cp = yyg->yy_c_buf_p; yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of user's declarations */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; char *source = yyg->yytext_ptr; int number_to_move, i; int ret_val; if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; int yy_c_buf_p_offset = (int) (yyg->yy_c_buf_p - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc( (void *) b->yy_ch_buf, (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = NULL; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), yyg->yy_n_chars, num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } if ( yyg->yy_n_chars == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart( yyin , yyscanner); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); /* "- 2" to take care of EOB's */ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); } yyg->yy_n_chars += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (yyscan_t yyscanner) { yy_state_type yy_current_state; char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_current_state = yyg->yy_start; for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) { YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 40 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) { int yy_is_jam; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ char *yy_cp = yyg->yy_c_buf_p; YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 40 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; yy_is_jam = (yy_current_state == 39); (void)yyg; return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (yyscan_t yyscanner) #else static int input (yyscan_t yyscanner) #endif { int c; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; *yyg->yy_c_buf_p = yyg->yy_hold_char; if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) /* This was really a NUL. */ *yyg->yy_c_buf_p = '\0'; else { /* need more input */ int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); ++yyg->yy_c_buf_p; switch ( yy_get_next_buffer( yyscanner ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart( yyin , yyscanner); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( yyscanner ) ) return 0; if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(yyscanner); #else return input(yyscanner); #endif } case EOB_ACT_CONTINUE_SCAN: yyg->yy_c_buf_p = yyg->yytext_ptr + offset; break; } } } c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ yyg->yy_hold_char = *++yyg->yy_c_buf_p; if ( c == '\n' ) do{ yylineno++; yycolumn=0; }while(0) ; return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * @param yyscanner The scanner object. * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (yyscanner); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); } yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); yy_load_buffer_state( yyscanner ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * @param yyscanner The scanner object. */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (yyscanner); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *yyg->yy_c_buf_p = yyg->yy_hold_char; YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( yyscanner ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ yyg->yy_did_buffer_switch_on_eof = 1; } static void yy_load_buffer_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; yyg->yy_hold_char = *yyg->yy_c_buf_p; } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * @param yyscanner The scanner object. * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer( b, file , yyscanner); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * @param yyscanner The scanner object. */ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree( (void *) b->yy_ch_buf , yyscanner ); yyfree( (void *) b , yyscanner ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) { int oerrno = errno; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_flush_buffer( b , yyscanner); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * @param yyscanner The scanner object. */ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( yyscanner ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * @param yyscanner The scanner object. */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (new_buffer == NULL) return; yyensure_buffer_stack(yyscanner); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *yyg->yy_c_buf_p = yyg->yy_hold_char; YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) yyg->yy_buffer_stack_top++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( yyscanner ); yyg->yy_did_buffer_switch_on_eof = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * @param yyscanner The scanner object. */ void yypop_buffer_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); YY_CURRENT_BUFFER_LVALUE = NULL; if (yyg->yy_buffer_stack_top > 0) --yyg->yy_buffer_stack_top; if (YY_CURRENT_BUFFER) { yy_load_buffer_state( yyscanner ); yyg->yy_did_buffer_switch_on_eof = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (yyscan_t yyscanner) { yy_size_t num_to_alloc; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (!yyg->yy_buffer_stack) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); if ( ! yyg->yy_buffer_stack ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); yyg->yy_buffer_stack_max = num_to_alloc; yyg->yy_buffer_stack_top = 0; return; } if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ /* Increase the buffer to prepare for a possible push. */ yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = yyg->yy_buffer_stack_max + grow_size; yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc (yyg->yy_buffer_stack, num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); if ( ! yyg->yy_buffer_stack ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); /* zero only the new slots.*/ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); yyg->yy_buffer_stack_max = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return NULL; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = NULL; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer( b , yyscanner ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * @param yyscanner The scanner object. * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) { return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param yybytes the byte buffer to scan * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = (yy_size_t) (_yybytes_len + 2); buf = (char *) yyalloc( n , yyscanner ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer( buf, n , yyscanner); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = yyg->yy_hold_char; \ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ yyg->yy_hold_char = *yyg->yy_c_buf_p; \ *yyg->yy_c_buf_p = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the user-defined data for this scanner. * @param yyscanner The scanner object. */ YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyextra; } /** Get the current line number. * @param yyscanner The scanner object. */ int yyget_lineno (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (! YY_CURRENT_BUFFER) return 0; return yylineno; } /** Get the current column number. * @param yyscanner The scanner object. */ int yyget_column (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (! YY_CURRENT_BUFFER) return 0; return yycolumn; } /** Get the input stream. * @param yyscanner The scanner object. */ FILE *yyget_in (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyin; } /** Get the output stream. * @param yyscanner The scanner object. */ FILE *yyget_out (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyout; } /** Get the length of the current token. * @param yyscanner The scanner object. */ int yyget_leng (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyleng; } /** Get the current token. * @param yyscanner The scanner object. */ char *yyget_text (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yytext; } /** Set the user-defined data. This data is never touched by the scanner. * @param user_defined The data to be associated with this scanner. * @param yyscanner The scanner object. */ void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyextra = user_defined ; } /** Set the current line number. * @param _line_number line number * @param yyscanner The scanner object. */ void yyset_lineno (int _line_number , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* lineno is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); yylineno = _line_number; } /** Set the current column. * @param _column_no column number * @param yyscanner The scanner object. */ void yyset_column (int _column_no , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* column is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) YY_FATAL_ERROR( "yyset_column called with no buffer" ); yycolumn = _column_no; } /** Set the input stream. This does not discard the current * input buffer. * @param _in_str A readable stream. * @param yyscanner The scanner object. * @see yy_switch_to_buffer */ void yyset_in (FILE * _in_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyin = _in_str ; } void yyset_out (FILE * _out_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyout = _out_str ; } int yyget_debug (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yy_flex_debug; } void yyset_debug (int _bdebug , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_flex_debug = _bdebug ; } /* Accessor methods for yylval and yylloc */ YYSTYPE * yyget_lval (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yylval; } void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yylval = yylval_param; } /* User-visible API */ /* yylex_init is special because it creates the scanner itself, so it is * the ONLY reentrant function that doesn't take the scanner as the last argument. * That's why we explicitly handle the declaration, instead of using our macros. */ int yylex_init(yyscan_t* ptr_yy_globals) { if (ptr_yy_globals == NULL){ errno = EINVAL; return 1; } *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); if (*ptr_yy_globals == NULL){ errno = ENOMEM; return 1; } /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); return yy_init_globals ( *ptr_yy_globals ); } /* yylex_init_extra has the same functionality as yylex_init, but follows the * convention of taking the scanner as the last argument. Note however, that * this is a *pointer* to a scanner, as it will be allocated by this call (and * is the reason, too, why this function also must handle its own declaration). * The user defined value in the first argument will be available to yyalloc in * the yyextra field. */ int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) { struct yyguts_t dummy_yyguts; yyset_extra (yy_user_defined, &dummy_yyguts); if (ptr_yy_globals == NULL){ errno = EINVAL; return 1; } *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); if (*ptr_yy_globals == NULL){ errno = ENOMEM; return 1; } /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); yyset_extra (yy_user_defined, *ptr_yy_globals); return yy_init_globals ( *ptr_yy_globals ); } static int yy_init_globals (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ yyg->yy_buffer_stack = NULL; yyg->yy_buffer_stack_top = 0; yyg->yy_buffer_stack_max = 0; yyg->yy_c_buf_p = NULL; yyg->yy_init = 0; yyg->yy_start = 0; yyg->yy_start_stack_ptr = 0; yyg->yy_start_stack_depth = 0; yyg->yy_start_stack = NULL; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = NULL; yyout = NULL; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(yyscanner); } /* Destroy the stack itself. */ yyfree(yyg->yy_buffer_stack , yyscanner); yyg->yy_buffer_stack = NULL; /* Destroy the start condition stack. */ yyfree( yyg->yy_start_stack , yyscanner ); yyg->yy_start_stack = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( yyscanner); /* Destroy the main struct (reentrant only). */ yyfree ( yyscanner , yyscanner ); yyscanner = NULL; return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (const char * s , yyscan_t yyscanner) { int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; return malloc(size); } void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return realloc(ptr, size); } void yyfree (void * ptr , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" #line 215 "libyara/hex_lexer.l" // // yyfatal (actually named hex_yyfatal because of the '%option prefix="hex_yy"' // directive) is called when a fatal error occurs in the parser. When this // happens we are deep inside the parsing logic generated by flex/bison and // the only way to exit gracefully from there is using setjmp/longjmp. // void yyfatal( yyscan_t yyscanner, const char *error_message) { jmp_buf* recovery_trampoline = (jmp_buf*) yr_thread_storage_get_value( &yr_yyfatal_trampoline_tls); // Never returns. longjmp(*recovery_trampoline, 1); } void yyerror( yyscan_t yyscanner, HEX_LEX_ENVIRONMENT* lex_env, const char *error_message) { // if lex_env->last_error was set to some error code before // don't overwrite it, we are interested in the first error, not in // subsequent errors like "syntax error, unexpected $end" caused by // early parser termination. if (lex_env->last_error == ERROR_SUCCESS) { lex_env->last_error = ERROR_INVALID_HEX_STRING; strlcpy( lex_env->last_error_message, error_message, sizeof(lex_env->last_error_message)); } } int yr_parse_hex_string( const char* hex_string, RE_AST** re_ast, RE_ERROR* error) { yyscan_t yyscanner; jmp_buf recovery_trampoline; HEX_LEX_ENVIRONMENT lex_env; lex_env.last_error = ERROR_SUCCESS; lex_env.inside_or = 0; yr_thread_storage_set_value( &yr_yyfatal_trampoline_tls, &recovery_trampoline); if (setjmp(recovery_trampoline) != 0) return ERROR_INTERNAL_FATAL_ERROR; FAIL_ON_ERROR(yr_re_ast_create(re_ast)); // The RE_FLAGS_FAST_REGEXP flag indicates a regular expression can be // matched by faster algorithm. These regular expressions come from hex // strings that do not contain alternatives, like in: // // { ( 01 02 | 03 04) 05 06 }. // // This flag is unset later during parsing if alternatives are used. (*re_ast)->flags |= RE_FLAGS_FAST_REGEXP; // Set RE_FLAGS_DOT_ALL because in hex strings the "dot" (?? in this case) // must match all characters including new-line. (*re_ast)->flags |= RE_FLAGS_DOT_ALL; if (yylex_init(&yyscanner) != 0) { yr_re_ast_destroy(*re_ast); *re_ast = NULL; return ERROR_INSUFFICIENT_MEMORY; } yyset_extra(*re_ast, yyscanner); yy_scan_string(hex_string, yyscanner); yyparse(yyscanner, &lex_env); yylex_destroy(yyscanner); if (lex_env.last_error != ERROR_SUCCESS) { strlcpy(error->message, lex_env.last_error_message, sizeof(error->message)); return lex_env.last_error; } return ERROR_SUCCESS; } yara-4.5.3/libyara/hex_lexer.l000066400000000000000000000157241501365277300162640ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Lexical analyzer for hex strings */ %{ /* Disable warnings for unused functions in this file. As we redefine YY_FATAL_ERROR macro to use our own function hex_yyfatal, the yy_fatal_error function generated by Flex is not actually used, causing a compiler warning. Flex doesn't offer any options to remove the yy_fatal_error function. When they include something like %option noyy_fatal_error as they do with noyywrap then we can remove this pragma. */ #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wunused-function" #endif #include #include #include #include #include #include #include #include #include #include "hex_grammar.h" #ifdef _WIN32 #define snprintf _snprintf #endif #define ERROR_IF(x, error) \ if (x) \ { \ RE_AST* re_ast = yyget_extra(yyscanner); \ re_ast->error_code = error; \ YYABORT; \ } \ %} %option reentrant bison-bridge %option noyywrap %option nounistd %option noinput %option nounput %option never-interactive %option yylineno %option prefix="hex_yy" %option outfile="lex.yy.c" %option verbose %option warn digit [0-9] letter [a-zA-Z] hexdigit [a-fA-F0-9] %x comment %x range %% {hexdigit}{2} { yylval->integer = xtoi(yytext); return _BYTE_; } {hexdigit}\? { yytext[1] = '0'; // replace ? by 0 yylval->integer = xtoi(yytext) | 0xF000 ; return _MASKED_BYTE_; } \~{hexdigit}{2} { yylval->integer = xtoi(&(yytext[1])); return _NOT_BYTE_; } \?{hexdigit} { yytext[0] = '0'; // replace ? by 0 yylval->integer = xtoi(yytext) | 0x0F00 ; return _MASKED_BYTE_; } \?\? { yylval->integer = 0x0000; return _MASKED_BYTE_; } \~{hexdigit}\? { yytext[2] = '0'; // replace ? by 0 yylval->integer = xtoi(&(yytext[1])) | 0xF000 ; return _MASKED_NOT_BYTE_; } \~\?{hexdigit} { yytext[1] = '0'; // replace ? by 0 yylval->integer = xtoi(&(yytext[1])) | 0x0F00 ; return _MASKED_NOT_BYTE_; } {hexdigit} { yyerror(yyscanner, lex_env, "uneven number of digits in hex string"); yyterminate(); } \~ { yyerror(yyscanner, lex_env, "invalid not operator (~) in hex string"); yyterminate(); } \[ { BEGIN(range); return yytext[0]; } "/*" { BEGIN(comment); } "*/" { BEGIN(INITIAL); } .|\n // skip comments "//".* // skip single-line comments \- { return yytext[0]; } {digit}+ { yylval->integer = atoi(yytext); return _NUMBER_; } \] { BEGIN(INITIAL); return yytext[0]; } [ \t\r\n] // skip whitespaces . { yyerror(yyscanner, lex_env, "invalid character in hex string jump"); yyterminate(); } [ \t\r\n] // skip whitespaces [{}()|] { // pass valid characters to the parser return yytext[0]; } . { // reject all other characters yyerror(yyscanner, lex_env, "invalid character in hex string"); yyterminate(); } %% // // yyfatal (actually named hex_yyfatal because of the '%option prefix="hex_yy"' // directive) is called when a fatal error occurs in the parser. When this // happens we are deep inside the parsing logic generated by flex/bison and // the only way to exit gracefully from there is using setjmp/longjmp. // void yyfatal( yyscan_t yyscanner, const char *error_message) { jmp_buf* recovery_trampoline = (jmp_buf*) yr_thread_storage_get_value( &yr_yyfatal_trampoline_tls); // Never returns. longjmp(*recovery_trampoline, 1); } void yyerror( yyscan_t yyscanner, HEX_LEX_ENVIRONMENT* lex_env, const char *error_message) { // if lex_env->last_error was set to some error code before // don't overwrite it, we are interested in the first error, not in // subsequent errors like "syntax error, unexpected $end" caused by // early parser termination. if (lex_env->last_error == ERROR_SUCCESS) { lex_env->last_error = ERROR_INVALID_HEX_STRING; strlcpy( lex_env->last_error_message, error_message, sizeof(lex_env->last_error_message)); } } int yr_parse_hex_string( const char* hex_string, RE_AST** re_ast, RE_ERROR* error) { yyscan_t yyscanner; jmp_buf recovery_trampoline; HEX_LEX_ENVIRONMENT lex_env; lex_env.last_error = ERROR_SUCCESS; lex_env.inside_or = 0; yr_thread_storage_set_value( &yr_yyfatal_trampoline_tls, &recovery_trampoline); if (setjmp(recovery_trampoline) != 0) return ERROR_INTERNAL_FATAL_ERROR; FAIL_ON_ERROR(yr_re_ast_create(re_ast)); // The RE_FLAGS_FAST_REGEXP flag indicates a regular expression can be // matched by faster algorithm. These regular expressions come from hex // strings that do not contain alternatives, like in: // // { ( 01 02 | 03 04) 05 06 }. // // This flag is unset later during parsing if alternatives are used. (*re_ast)->flags |= RE_FLAGS_FAST_REGEXP; // Set RE_FLAGS_DOT_ALL because in hex strings the "dot" (?? in this case) // must match all characters including new-line. (*re_ast)->flags |= RE_FLAGS_DOT_ALL; if (yylex_init(&yyscanner) != 0) { yr_re_ast_destroy(*re_ast); *re_ast = NULL; return ERROR_INSUFFICIENT_MEMORY; } yyset_extra(*re_ast, yyscanner); yy_scan_string(hex_string, yyscanner); yyparse(yyscanner, &lex_env); yylex_destroy(yyscanner); if (lex_env.last_error != ERROR_SUCCESS) { strlcpy(error->message, lex_env.last_error_message, sizeof(error->message)); return lex_env.last_error; } return ERROR_SUCCESS; } yara-4.5.3/libyara/include/000077500000000000000000000000001501365277300155365ustar00rootroot00000000000000yara-4.5.3/libyara/include/authenticode-parser/000077500000000000000000000000001501365277300215045ustar00rootroot00000000000000yara-4.5.3/libyara/include/authenticode-parser/authenticode.h000066400000000000000000000206641501365277300243410ustar00rootroot00000000000000/* Copyright (c) 2021 Avast Software 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 AUTHENTICODE_PARSER_AUTHENTICODE_H #define AUTHENTICODE_PARSER_AUTHENTICODE_H #ifdef __cplusplus extern "C" { #endif #include #include /* Signature is valid */ #define AUTHENTICODE_VFY_VALID 0 /* Parsing error (from OpenSSL functions) */ #define AUTHENTICODE_VFY_CANT_PARSE 1 /* Signers certificate is missing */ #define AUTHENTICODE_VFY_NO_SIGNER_CERT 2 /* No digest saved inside the signature */ #define AUTHENTICODE_VFY_DIGEST_MISSING 3 /* Non verification errors - allocations etc. */ #define AUTHENTICODE_VFY_INTERNAL_ERROR 4 /* SignerInfo part of PKCS7 is missing */ #define AUTHENTICODE_VFY_NO_SIGNER_INFO 5 /* PKCS7 doesn't have type of SignedData, can't proceed */ #define AUTHENTICODE_VFY_WRONG_PKCS7_TYPE 6 /* PKCS7 doesn't have corrent content, can't proceed */ #define AUTHENTICODE_VFY_BAD_CONTENT 7 /* Contained and calculated digest don't match */ #define AUTHENTICODE_VFY_INVALID 8 /* Signature hash and file hash doesn't match */ #define AUTHENTICODE_VFY_WRONG_FILE_DIGEST 9 /* Unknown algorithm, can't proceed with verification */ #define AUTHENTICODE_VFY_UNKNOWN_ALGORITHM 10 /* Countersignature is valid */ #define COUNTERSIGNATURE_VFY_VALID 0 /* Parsing error (from OpenSSL functions) */ #define COUNTERSIGNATURE_VFY_CANT_PARSE 1 /* Signers certificate is missing */ #define COUNTERSIGNATURE_VFY_NO_SIGNER_CERT 2 /* Unknown algorithm, can't proceed with verification */ #define COUNTERSIGNATURE_VFY_UNKNOWN_ALGORITHM 3 /* Verification failed, digest mismatch */ #define COUNTERSIGNATURE_VFY_INVALID 4 /* Failed to decrypt countersignature enc_digest for verification */ #define COUNTERSIGNATURE_VFY_CANT_DECRYPT_DIGEST 5 /* No digest saved inside the countersignature */ #define COUNTERSIGNATURE_VFY_DIGEST_MISSING 6 /* Message digest inside countersignature doesn't match signature it countersigns */ #define COUNTERSIGNATURE_VFY_DOESNT_MATCH_SIGNATURE 7 /* Non verification errors - allocations etc. */ #define COUNTERSIGNATURE_VFY_INTERNAL_ERROR 8 /* Time is missing in the timestamp signature */ #define COUNTERSIGNATURE_VFY_TIME_MISSING 9 typedef struct { uint8_t* data; int len; } ByteArray; typedef struct { /* Various X509 attributes parsed out in raw bytes*/ ByteArray country; ByteArray organization; ByteArray organizationalUnit; ByteArray nameQualifier; ByteArray state; ByteArray commonName; ByteArray serialNumber; ByteArray locality; ByteArray title; ByteArray surname; ByteArray givenName; ByteArray initials; ByteArray pseudonym; ByteArray generationQualifier; ByteArray emailAddress; } Attributes; typedef struct { long version; /* Raw version of X509 */ char* issuer; /* Oneline name of Issuer */ char* subject; /* Oneline name of Subject */ char* serial; /* Serial number in format 00:01:02:03:04... */ ByteArray sha1; /* SHA1 of the DER representation of the cert */ ByteArray sha256; /* SHA256 of the DER representation of the cert */ char* key_alg; /* Name of the key algorithm */ char* sig_alg; /* Name of the signature algorithm */ char* sig_alg_oid; /* OID of the signature algorithm */ int64_t not_before; /* NotBefore validity */ int64_t not_after; /* NotAfter validity */ char* key; /* PEM encoded public key */ Attributes issuer_attrs; /* Parsed X509 Attributes of Issuer */ Attributes subject_attrs; /* Parsed X509 Attributes of Subject */ } Certificate; typedef struct { Certificate** certs; size_t count; } CertificateArray; typedef struct { int verify_flags; /* COUNTERISGNATURE_VFY_ flag */ int64_t sign_time; /* Signing time of the timestamp countersignature */ char* digest_alg; /* Name of the digest algorithm used */ ByteArray digest; /* Stored message digest */ CertificateArray* chain; /* Certificate chain of the signer */ CertificateArray* certs; /* All certs stored inside Countersignature, this can be superset of chain in case of non PKCS9 countersignature*/ } Countersignature; typedef struct { Countersignature** counters; size_t count; } CountersignatureArray; typedef struct { /* Represents SignerInfo structure */ ByteArray digest; /* Message Digest of the SignerInfo */ char* digest_alg; /* name of the digest algorithm */ char* program_name; /* Program name stored in SpcOpusInfo structure of Authenticode */ CertificateArray* chain; /* Certificate chain of the signer */ } Signer; typedef struct { int verify_flags; /* AUTHENTICODE_VFY_ flag */ int version; /* Raw PKCS7 version */ char* digest_alg; /* name of the digest algorithm */ ByteArray digest; /* File Digest stored in the Signature */ ByteArray file_digest; /* Actual calculated file digest */ Signer* signer; /* SignerInfo information of the Authenticode */ CertificateArray* certs; /* All certificates in the Signature including the ones in timestamp countersignatures */ CountersignatureArray* countersigs; /* Array of timestamp countersignatures */ } Authenticode; typedef struct { Authenticode** signatures; size_t count; } AuthenticodeArray; /** * @brief Initializes all globals OpenSSl objects we need for parsing, this is not thread-safe and * needs to be called only once, before any multithreading environment * https://github.com/openssl/openssl/issues/13524 */ void initialize_authenticode_parser(); /** * @brief Constructs AuthenticodeArray from PE file data. Authenticode can * contains nested Authenticode signatures as its unsigned attribute, * which can also contain nested signatures. For this reason the function returns * an Array of parsed Authenticode signatures. Any field of the parsed out * structures can be NULL, depending on the input data. * Verification result is stored in verify_flags with the first verification error. * * @param pe_data PE binary data * @param pe_len * @return AuthenticodeArray* */ AuthenticodeArray* parse_authenticode(const uint8_t* pe_data, uint64_t pe_len); /** * @brief Constructs AuthenticodeArray from binary data containing Authenticode * signature. Authenticode can contains nested Authenticode signatures * as its unsigned attribute, which can also contain nested signatures. * For this reason the function return an Array of parsed Authenticode signatures. * Any field of the parsed out structures can be NULL, depending on the input data. * WARNING: in case of this interface, the file and signature digest comparison is * up to the library user, as there is no pe data to calculate file digest from. * Verification result is stored in verify_flags with the first verification error * * @param data Binary data containing Authenticode signature * @param len * @return AuthenticodeArray* */ AuthenticodeArray* authenticode_new(const uint8_t* data, int32_t len); /** * @brief Deallocates AuthenticodeArray and all it's allocated members * * @param auth */ void authenticode_array_free(AuthenticodeArray* auth); #ifdef __cplusplus } #endif #endif yara-4.5.3/libyara/include/tlshc/000077500000000000000000000000001501365277300166535ustar00rootroot00000000000000yara-4.5.3/libyara/include/tlshc/tlsh.h000066400000000000000000000035631501365277300200050ustar00rootroot00000000000000#ifndef __TLSH_TLSH_H__ #define __TLSH_TLSH_H__ #include #define TLSH_OPTION_CONSERVATIVE 2 #define TLSH_OPTION_KEEP_BUCKET 4 #define TLSH_OPTION_PRIVATE 8 #define TLSH_OPTION_THREADED 16 // Define TLSH_STRING_LEN_REQ, which is the string length of "T1" + the hex // value of the Tlsh hash. BUCKETS_256 & CHECKSUM_3B are compiler switches // defined in CMakeLists.txt #if defined BUCKETS_256 #define TLSH_STRING_LEN_REQ 136 // changed the minimum data length to 256 for version 3.3 #define MIN_DATA_LENGTH 50 // added the -force option for version 3.5 // added the -conservatibe option for version 3.17 #define MIN_CONSERVATIVE_DATA_LENGTH 256 #endif #if defined BUCKETS_128 #define TLSH_STRING_LEN_REQ 72 // changed the minimum data length to 256 for version 3.3 #define MIN_DATA_LENGTH 50 // added the -force option for version 3.5 // added the -conservatibe option for version 3.17 #define MIN_CONSERVATIVE_DATA_LENGTH 256 #endif #if defined BUCKETS_48 // No 3 Byte checksum option for 48 Bucket min hash #define TLSH_STRING_LEN 30 // changed the minimum data length to 256 for version 3.3 #define MIN_DATA_LENGTH 10 // added the -force option for version 3.5 #define MIN_CONSERVATIVE_DATA_LENGTH 10 #endif #define TLSH_STRING_BUFFER_LEN (TLSH_STRING_LEN_REQ + 1) #ifdef __cplusplus extern "C" { #endif typedef struct TlshImpl TlshImpl; typedef struct { TlshImpl* impl; } Tlsh; Tlsh* tlsh_new(); void tlsh_free(Tlsh* tlsh); void tlsh_reset(Tlsh* tlsh); int tlsh_update(Tlsh* tlsh, const unsigned char* data, unsigned int len); int tlsh_final(Tlsh* tlsh, const unsigned char* data, unsigned int len, int tlsh_option); const char* tlsh_get_hash(Tlsh* tlsh, bool showvers); #ifdef __cplusplus } #endif #endif // __TLSH_TLSH_H__yara-4.5.3/libyara/include/yara.h000066400000000000000000000034661501365277300166540ustar00rootroot00000000000000/* Copyright (c) 2007-2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_YARA_H #define YR_YARA_H #include "yara/compiler.h" #include "yara/error.h" #include "yara/filemap.h" #include "yara/hash.h" #include "yara/libyara.h" #include "yara/mem.h" #include "yara/modules.h" #include "yara/object.h" #include "yara/scanner.h" #include "yara/stream.h" #include "yara/strutils.h" #include "yara/utils.h" #endif yara-4.5.3/libyara/include/yara/000077500000000000000000000000001501365277300164725ustar00rootroot00000000000000yara-4.5.3/libyara/include/yara/ahocorasick.h000066400000000000000000000051551501365277300211370ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _AHOCORASICK_H #define _AHOCORASICK_H #include #include #include // Number of bits dedicated to store the offset of the slot relative to its // own state. #define YR_AC_SLOT_OFFSET_BITS 9 // Max number of slots in the transition table. This is the maximum number of // slots that can be addressed with 23-bit indexes. #define YR_AC_MAX_TRANSITION_TABLE_SIZE 0x800000 #define YR_AC_ROOT_STATE 0 #define YR_AC_NEXT_STATE(t) (t >> YR_AC_SLOT_OFFSET_BITS) #define YR_AC_INVALID_TRANSITION(t, c) (((t) &0x1FF) != c) #define YR_AC_MAKE_TRANSITION(state, code) \ ((YR_AC_TRANSITION)( \ (((YR_AC_TRANSITION) state) << YR_AC_SLOT_OFFSET_BITS) | (code))) int yr_ac_automaton_create(YR_ARENA* arena, YR_AC_AUTOMATON** automaton); int yr_ac_automaton_destroy(YR_AC_AUTOMATON* automaton); int yr_ac_add_string( YR_AC_AUTOMATON* automaton, YR_STRING* string, uint32_t string_idx, YR_ATOM_LIST_ITEM* atom, YR_ARENA* arena); int yr_ac_compile(YR_AC_AUTOMATON* automaton, YR_ARENA* arena); void yr_ac_print_automaton(YR_AC_AUTOMATON* automaton); #endif yara-4.5.3/libyara/include/yara/arena.h000066400000000000000000000214441501365277300177360ustar00rootroot00000000000000/* Copyright (c) 2020. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_ARENA_H #define YR_ARENA_H #include #include #include #include #define EOL ((size_t) -1) #define YR_ARENA_FILE_VERSION 21 #define YR_ARENA_NULL_REF \ (YR_ARENA_REF) \ { \ UINT32_MAX, UINT32_MAX \ } #define YR_ARENA_IS_NULL_REF(ref) \ (memcmp(&(ref), &YR_ARENA_NULL_REF, sizeof(YR_ARENA_NULL_REF)) == 0) typedef uint32_t yr_arena_off_t; typedef struct YR_ARENA YR_ARENA; typedef struct YR_ARENA_BUFFER YR_ARENA_BUFFER; typedef struct YR_ARENA_REF YR_ARENA_REF; typedef struct YR_RELOC YR_RELOC; // The YR_ARENA_REF must be 64-bits long because this structure occupies // the place of relocatable pointers when arenas are saved to file. The pack(4) // directive ensures that fields are aligned to 4-byte boundaries and the total // size of the structure is 8 bytes. When compiling YARA for 32-bits, pointers // are 4 bytes but this structure is still 8 bytes. For that reason structures // that are saved in arenas must declare pointers using the DECLARE_REFERENCE // macro, which ensures that 8 bytes are reserved for the pointer no matter if // they are 32-bits pointers. #pragma pack(push) #pragma pack(4) struct YR_ARENA_REF { uint32_t buffer_id; yr_arena_off_t offset; }; #pragma pack(pop) struct YR_ARENA_BUFFER { // Pointer the buffer's data. uint8_t* data; // Total buffer size, including the used and unused areas. The maximum size // allowed for a buffer is 4GB because offsets in YR_ARENA_REF are 32-bit // integers. size_t size; // Number of bytes that are actually used (equal to or lower than size). size_t used; }; struct YR_RELOC { // Buffer ID associated to this relocation entry. uint32_t buffer_id; // Offset within the buffer where the relocatable pointer resides. yr_arena_off_t offset; // Pointer to the next entry in the list. struct YR_RELOC* next; }; /* YR_ARENA is the structure that represents an arena. An arena is a set of buffers in which you can write arbitrary data. When the arena is created you can specify how many buffers it will have, this number is limited by YR_MAX_ARENA_BUFFERS. Buffers are numbered 0, 1, 2, and so on, and they are referenced by its number. Initially each buffer will have a size that is determined by an argument passed to yr_create_arena, but the size will grow automatically as you write data into it. When the buffer is re-sized it may be moved to a different location in memory, which means that any pointer you hold to data contained in the buffer is valid only until the next call to a function that may cause a buffer re-sizing. For long-lived references to data in a buffer you should use a YR_ARENA_REF, which is simply a struct storing the buffer number and the offset of the data relative to the beginning of the buffer. Such YR_ARENA_REF structures are returned by all functions that allocate space or write data in a buffer. The yr_arena_get_ptr function can be used for getting a pointer to data stored in the buffer given its offset, but this pointer should be used with only in a limited scope where you can be sure that your program is not calling a function that may cause a buffer re-sizing, like yr_arena_allocate_xxx and yr_arena_write_xxx. Arenas can also keep track pointers stored in some of its buffers that point to some location within the arena (it can be to the same buffer or a different one within the same arena). This is done with yr_arena_make_ptr_relocatable, this function receives a buffer number and an offset, and it tells the arena that the pointer stored at that particular location of the buffer must be adjusted every time the memory it points to is moved around. The yr_arena_allocate_struct function is an even more powerful mechanism for tracking relocatable pointers. This function allows to allocate space in a buffer for a structure, while at the same time telling the arena which fields in the structure are relocatable pointers. */ struct YR_ARENA { // Number of users of this arena. This is set to one when the arena is // created, and can be incremented by calling yr_arena_acquire. On each call // to yr_arena_release it gets decremented by one, if xrefs reaches zero // the buffers and the YR_ARENA structures are freed. uint32_t xrefs; // Number of buffers in this arena. uint32_t num_buffers; // Status of individual buffers. YR_ARENA_BUFFER buffers[YR_MAX_ARENA_BUFFERS]; // Initial size for each buffer. size_t initial_buffer_size; // Head of the list containing relocation entries. YR_RELOC* reloc_list_head; // Tail of the list containing relocation entries. YR_RELOC* reloc_list_tail; }; // Creates an arena with the specified number of buffers and takes ownership of // it. Initially each buffer is empty, the first time that some data is written // into a buffer at least initial_buffer_size are reserved for the buffer. int yr_arena_create( uint32_t num_buffers, size_t initial_buffer_size, YR_ARENA** arena); // Takes ownership of the arena. void yr_arena_acquire(YR_ARENA* arena); // Release ownership of the arena. If the number of owners drops to zero the // arena is destroyed and all its resources are freed. int yr_arena_release(YR_ARENA* arena); // Given a reference to some data within the arena, it returns a pointer to // the data. This pointer is valid only until the next call to any of the // functions that allocates space in the buffer where the data resides, like // yr_arena_allocate_xxx and yr_arena_write_xxx. These functions can cause // the buffer to be moved to different memory location and the pointer won't // valid any longer. void* yr_arena_ref_to_ptr(YR_ARENA* arena, YR_ARENA_REF* ref); // Given a pointer into the arena, it returns a reference to it. The reference // can be used with yr_arena_ref_to_ptr to obtain a pointer again. Unlike // pointers, references are during the arena's lifetime, even if the buffers // are moved to a different memory location. int yr_arena_ptr_to_ref( YR_ARENA* arena, const void* address, YR_ARENA_REF* ref); // Given a buffer number and an offset within the buffer, returns a pointer // to that offset. The same limitations explained for yr_arena_ref_to_ptr // applies for the pointers returned by this function. void* yr_arena_get_ptr( YR_ARENA* arena, uint32_t buffer_id, yr_arena_off_t offset); yr_arena_off_t yr_arena_get_current_offset(YR_ARENA* arena, uint32_t buffer_id); int yr_arena_allocate_memory( YR_ARENA* arena, uint32_t buffer_id, size_t size, YR_ARENA_REF* ref); int yr_arena_allocate_zeroed_memory( YR_ARENA* arena, uint32_t buffer_id, size_t size, YR_ARENA_REF* ref); int yr_arena_allocate_struct( YR_ARENA* arena, uint32_t buffer_id, size_t size, YR_ARENA_REF* ref, ...); int yr_arena_make_ptr_relocatable(YR_ARENA* arena, uint32_t buffer_id, ...); int yr_arena_write_data( YR_ARENA* arena, uint32_t buffer_id, const void* data, size_t size, YR_ARENA_REF* ref); int yr_arena_write_string( YR_ARENA* arena, uint32_t buffer_id, const char* string, YR_ARENA_REF* ref); int yr_arena_write_uint32( YR_ARENA* arena, uint32_t buffer_id, uint32_t integer, YR_ARENA_REF* ref); int yr_arena_load_stream(YR_STREAM* stream, YR_ARENA** arena); int yr_arena_save_stream(YR_ARENA* arena, YR_STREAM* stream); #endif // YR_ARENA_H yara-4.5.3/libyara/include/yara/atoms.h000066400000000000000000000072321501365277300177720ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_ATOMS_H #define YR_ATOMS_H #include #include #define ATOM_TREE_LEAF 1 #define ATOM_TREE_AND 2 #define ATOM_TREE_OR 3 typedef struct YR_ATOM YR_ATOM; typedef struct YR_ATOM_TREE_NODE YR_ATOM_TREE_NODE; typedef struct YR_ATOM_TREE YR_ATOM_TREE; typedef struct YR_ATOM_LIST_ITEM YR_ATOM_LIST_ITEM; typedef struct YR_ATOM_QUALITY_TABLE_ENTRY YR_ATOM_QUALITY_TABLE_ENTRY; typedef struct YR_ATOMS_CONFIG YR_ATOMS_CONFIG; struct YR_ATOM { uint8_t length; uint8_t bytes[YR_MAX_ATOM_LENGTH]; uint8_t mask[YR_MAX_ATOM_LENGTH]; }; struct YR_ATOM_TREE_NODE { uint8_t type; YR_ATOM atom; // RE nodes that correspond to each byte in the atom. RE_NODE* re_nodes[YR_MAX_ATOM_LENGTH]; YR_ATOM_TREE_NODE* children_head; YR_ATOM_TREE_NODE* children_tail; YR_ATOM_TREE_NODE* next_sibling; }; struct YR_ATOM_TREE { YR_ATOM_TREE_NODE* root_node; }; struct YR_ATOM_LIST_ITEM { YR_ATOM atom; uint16_t backtrack; YR_ARENA_REF forward_code_ref; YR_ARENA_REF backward_code_ref; YR_ATOM_LIST_ITEM* next; }; #pragma pack(push) #pragma pack(1) struct YR_ATOM_QUALITY_TABLE_ENTRY { const uint8_t atom[YR_MAX_ATOM_LENGTH]; const uint8_t quality; }; #pragma pack(pop) typedef int (*YR_ATOMS_QUALITY_FUNC)(YR_ATOMS_CONFIG* config, YR_ATOM* atom); struct YR_ATOMS_CONFIG { YR_ATOMS_QUALITY_FUNC get_atom_quality; YR_ATOM_QUALITY_TABLE_ENTRY* quality_table; int quality_warning_threshold; int quality_table_entries; bool free_quality_table; }; int yr_atoms_extract_from_re( YR_ATOMS_CONFIG* config, RE_AST* re_ast, YR_MODIFIER modifier, YR_ATOM_LIST_ITEM** atoms, int* min_atom_quality); int yr_atoms_extract_from_string( YR_ATOMS_CONFIG* config, uint8_t* string, int string_length, YR_MODIFIER modifier, YR_ATOM_LIST_ITEM** atoms, int* min_atom_quality); int yr_atoms_extract_triplets(RE_NODE* re_node, YR_ATOM_LIST_ITEM** atoms); int yr_atoms_heuristic_quality(YR_ATOMS_CONFIG* config, YR_ATOM* atom); int yr_atoms_table_quality(YR_ATOMS_CONFIG* config, YR_ATOM* atom); int yr_atoms_min_quality(YR_ATOMS_CONFIG* config, YR_ATOM_LIST_ITEM* atom_list); void yr_atoms_list_destroy(YR_ATOM_LIST_ITEM* list_head); #endif yara-4.5.3/libyara/include/yara/base64.h000066400000000000000000000035111501365277300177270ustar00rootroot00000000000000/* Copyright (c) 2020. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_BASE64_H #define YR_BASE64_H #include #include #include typedef struct BASE64_NODE BASE64_NODE; struct BASE64_NODE { SIZED_STRING* str; int escaped; BASE64_NODE* next; }; int yr_base64_ast_from_string( SIZED_STRING* in_str, YR_MODIFIER modifier, RE_AST** re_ast, RE_ERROR* error); #endif yara-4.5.3/libyara/include/yara/bitmask.h000066400000000000000000000066241501365277300203050ustar00rootroot00000000000000/* Copyright (c) 2018. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_BITMASK_H #define YR_BITMASK_H #include // // Utility macros for working with bitmaps. // // Declare a bitmask of n bits: // YR_BITMASK my_bitmask[YR_BITMASK_SIZE(n)]; // // Clear all bits: // yr_bitmask_clear_all(my_bitmask) // // Set bit n to 1: // yr_bitmask_set(my_bitmask, n) // // Clear bit n (set to 0): // yr_bitmask_clear(my_bitmask, n) // // Check if bit n is set: // yr_bitmask_is_set(my_bitmask, n) // #define YR_BITMASK unsigned long #define YR_BITMASK_SLOT_BITS (sizeof(YR_BITMASK) * 8) #define YR_BITMASK_SIZE(n) (((n) / (YR_BITMASK_SLOT_BITS)) + 1) #define yr_bitmask_set(bm, i) \ do \ { \ (bm)[(i) / YR_BITMASK_SLOT_BITS] |= 1UL << ((i) % YR_BITMASK_SLOT_BITS); \ } while (0) #define yr_bitmask_clear(bm, i) \ do \ { \ (bm)[(i) / YR_BITMASK_SLOT_BITS] &= ~( \ 1UL << ((i) % YR_BITMASK_SLOT_BITS)); \ } while (0) #define yr_bitmask_clear_all(bm) memset(bm, 0, sizeof(bm)) #define yr_bitmask_is_set(bm, i) \ ((bm)[(i) / YR_BITMASK_SLOT_BITS] & (1UL << ((i) % YR_BITMASK_SLOT_BITS))) #define yr_bitmask_is_not_set(bm, i) (!yr_bitmask_is_set(bm, i)) #define yr_bitmask_print(bm) \ { \ int i; \ for (i = 0; i < sizeof(bm) / sizeof(bm[0]); i++) \ { \ printf("%016lX\n", bm[i]); \ } \ } uint32_t yr_bitmask_find_non_colliding_offset( YR_BITMASK* a, YR_BITMASK* b, uint32_t len_a, uint32_t len_b, uint32_t* off_a); #endif yara-4.5.3/libyara/include/yara/compiler.h000066400000000000000000000335711501365277300204660ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_COMPILER_H #define YR_COMPILER_H #include #include #include #include #include #include #include #define YARA_ERROR_LEVEL_ERROR 0 #define YARA_ERROR_LEVEL_WARNING 1 // Expression type constants are powers of two because they are used as flags. #define EXPRESSION_TYPE_UNKNOWN 0 #define EXPRESSION_TYPE_BOOLEAN 1 #define EXPRESSION_TYPE_INTEGER 2 #define EXPRESSION_TYPE_STRING 4 #define EXPRESSION_TYPE_REGEXP 8 #define EXPRESSION_TYPE_OBJECT 16 #define EXPRESSION_TYPE_FLOAT 32 #define EXPRESSION_TYPE_QUANTIFIER 64 // The compiler uses an arena to store the data it generates during the // compilation. Each buffer in the arena is used for storing a different type // of data. The following identifiers indicate the purpose of each buffer. #define YR_NAMESPACES_TABLE 0 #define YR_RULES_TABLE 1 #define YR_METAS_TABLE 2 #define YR_STRINGS_TABLE 3 #define YR_EXTERNAL_VARIABLES_TABLE 4 #define YR_SZ_POOL 5 #define YR_CODE_SECTION 6 #define YR_RE_CODE_SECTION 7 #define YR_AC_TRANSITION_TABLE 8 #define YR_AC_STATE_MATCHES_TABLE 9 #define YR_AC_STATE_MATCHES_POOL 10 #define YR_SUMMARY_SECTION 11 // This is the number of buffers used by the compiler, should match the number // of items in the list above. #define YR_NUM_SECTIONS 12 // Number of variables used by loops. This doesn't include user defined // variables. #define YR_INTERNAL_LOOP_VARS 3 typedef struct _YR_ENUMERATION { int type; int count; } YR_ENUMERATION; typedef struct _YR_EXPRESSION { int type; union { int64_t integer; double double_; YR_OBJECT* object; YR_ARENA_REF sized_string_ref; } value; // Boolean expressions can hold a string count. If not empty, this indicates // that the condition can only be fulfilled if at least so many strings match. struct { int count; } required_strings; // An expression can have an associated identifier, if "ptr" is not NULL it // points to the identifier name, if it is NULL, then "ref" holds a reference // to the identifier within YR_SZ_POOL. When the identifier is in YR_SZ_POOL // a pointer can't be used as the YR_SZ_POOL can be moved to a different // memory location. struct { const char* ptr; YR_ARENA_REF ref; } identifier; } YR_EXPRESSION; typedef void (*YR_COMPILER_CALLBACK_FUNC)( int error_level, const char* file_name, int line_number, const YR_RULE* rule, const char* message, void* user_data); typedef const char* (*YR_COMPILER_INCLUDE_CALLBACK_FUNC)( const char* include_name, const char* calling_rule_filename, const char* calling_rule_namespace, void* user_data); typedef void (*YR_COMPILER_INCLUDE_FREE_FUNC)( const char* callback_result_ptr, void* user_data); typedef void (*YR_COMPILER_RE_AST_CALLBACK_FUNC)( const YR_RULE* rule, const char* string_identifier, const RE_AST* re_ast, void* user_data); typedef struct _YR_FIXUP { YR_ARENA_REF ref; struct _YR_FIXUP* next; } YR_FIXUP; // Each "for" loop in the condition has an associated context which holds // information about loop, like the target address for the jump instruction // that goes back to the beginning of the loop and the local variables used // by the loop. typedef struct _YR_LOOP_CONTEXT { // Reference indicating the the place in the code where the loop starts. The // loop goes back to this address on each iteration. YR_ARENA_REF start_ref; // vars_count is the number of local variables defined by the loop, and vars // is an array of expressions with the identifier and type for each of those // local variables. int vars_count; YR_EXPRESSION vars[YR_MAX_LOOP_VARS]; // vars_internal_count is the number of variables used by the loop which are // not defined by the rule itself but that are necessary for keeping the // loop's state. One example is the iteration counter. int vars_internal_count; } YR_LOOP_CONTEXT; typedef struct _YR_COMPILER { // Arena that contains the data generated by the compiled. The arena has // the following buffers: // // YR_SUMMARY_SECTION: // A YR_SUMMARY struct. // YR_RULES_TABLE: // An array of YR_RULE structures, one per each rule. // YR_STRINGS_TABLE: // An array of YR_STRING structures, one per each string. // YR_METAS_TABLE: // An array of YR_META structures, one per each meta definition. // YR_NAMESPACES_TABLE: // An array of YR_NAMESPACE structures, one per each namespace. // YR_EXTERNAL_VARIABLES_TABLE: // An array of YR_EXTERNAL_VARIABLE structures, one per each external // variable defined. // YR_SZ_POOL: // A collection of null-terminated strings. This buffer contains // identifiers, literal strings, and in general any null-terminated // string referenced by other data structures. // YR_CODE_SECTION: // The code for the condition section of all the rules. This is the // code executed by yr_execute_code. // YR_RE_CODE_SECTION: // Similar to YR_CODE_SECTION, but it contains the code for regular // expressions. This is the code executed by yr_re_exec and // yr_re_fast_exec. // YR_AC_TRANSITION_TABLE: // An array of uint32_t containing the Aho-Corasick transition table. // See comment in _yr_ac_build_transition_table for details. // YR_AC_STATE_MATCHES_TABLE: // An array of uint32_t with the same number of items than the transition // table. If entry N in the transition table corresponds to some // Aho-Corasick state, the N-th item in this array has the index within // the matches pool where the list of matches for that state begins. // YR_AC_STATE_MATCHES_POOL: // An array of YR_AC_MATCH structures. // YR_ARENA* arena; // Index of the rule being compiled in the array of YR_RULE structures // stored in YR_RULES_TABLE. If this is MAX_UINT32 the compiler is not // parsing a rule. uint32_t current_rule_idx; // Index of the rule that comes next during parsing. uint32_t next_rule_idx; // Index of the string being compiled in the array of YR_STRING structures // stored in YR_STRINGS_TABLE. uint32_t current_string_idx; // Index of the current namespace in the array of YR_NAMESPACE structures // stored in YR_NAMESPACES_TABLE. uint32_t current_namespace_idx; // Index of the current meta in the array of YR_META structures stored in // YR_METAS_TABLE. uint32_t current_meta_idx; // Pointer to a YR_RULES structure that represents the compiled rules. This // is what yr_compiler_get_rules returns. Once these rules are generated you // can't call any of the yr_compiler_add_xxx functions. YR_RULES* rules; int errors; int current_line; int last_error; int last_error_line; bool strict_escape; jmp_buf error_recovery; YR_AC_AUTOMATON* automaton; YR_HASH_TABLE* rules_table; YR_HASH_TABLE* objects_table; YR_HASH_TABLE* strings_table; // Hash table that contains all the identifiers with wildcards used in // conditions. This is used to make sure we error out if we are parsing a // rule _AFTER_ an existing rule has referenced it in a condition. For // example: // // rule a1 { condition: true } // rule b { condition: 1 of (a*) } // rule a2 { condition: true } // // This must be a compiler error when parsing a2 because b has already been // parsed and the instructions to check _ONLY_ a1 have been emitted. Rule b // has no concept of a2 and would not work as expected. YR_HASH_TABLE* wildcard_identifiers_table; // Hash table that contains all the strings that has been written to the // YR_SZ_POOL buffer in the compiler's arena. Values in the hash table are // the offset within the YR_SZ_POOL where the string resides. This allows to // know is some string has already been written in order to reuse instead of // writting it again. YR_HASH_TABLE* sz_table; YR_FIXUP* fixup_stack_head; int num_namespaces; YR_LOOP_CONTEXT loop[YR_MAX_LOOP_NESTING]; int loop_index; int loop_for_of_var_index; char* file_name_stack[YR_MAX_INCLUDE_DEPTH]; int file_name_stack_ptr; char last_error_extra_info[YR_MAX_COMPILER_ERROR_EXTRA_INFO]; // This buffer is used by the lexer for accumulating text strings. Those // strings are copied from flex's internal variables. lex_buf_ptr points to // the end of the string and lex_buf_len contains the number of bytes that // have been copied into lex_buf. char lex_buf[YR_LEX_BUF_SIZE]; char* lex_buf_ptr; unsigned short lex_buf_len; char include_base_dir[YR_MAX_PATH]; void* user_data; void* incl_clbk_user_data; void* re_ast_clbk_user_data; YR_COMPILER_CALLBACK_FUNC callback; YR_COMPILER_INCLUDE_CALLBACK_FUNC include_callback; YR_COMPILER_INCLUDE_FREE_FUNC include_free; YR_COMPILER_RE_AST_CALLBACK_FUNC re_ast_callback; YR_ATOMS_CONFIG atoms_config; } YR_COMPILER; #define yr_compiler_set_error_extra_info(compiler, info) \ strlcpy( \ compiler->last_error_extra_info, \ info, \ sizeof(compiler->last_error_extra_info)); #define yr_compiler_set_error_extra_info_fmt(compiler, fmt, ...) \ snprintf( \ compiler->last_error_extra_info, \ sizeof(compiler->last_error_extra_info), \ fmt, \ __VA_ARGS__); int _yr_compiler_push_file_name(YR_COMPILER* compiler, const char* file_name); void _yr_compiler_pop_file_name(YR_COMPILER* compiler); int _yr_compiler_get_var_frame(YR_COMPILER* compiler); const char* _yr_compiler_default_include_callback( const char* include_name, const char* calling_rule_filename, const char* calling_rule_namespace, void* user_data); YR_RULE* _yr_compiler_get_rule_by_idx(YR_COMPILER* compiler, uint32_t rule_idx); int _yr_compiler_store_string( YR_COMPILER* compiler, const char* string, YR_ARENA_REF* ref); int _yr_compiler_store_data( YR_COMPILER* compiler, const void* data, size_t data_length, YR_ARENA_REF* ref); YR_API int yr_compiler_create(YR_COMPILER** compiler); YR_API void yr_compiler_destroy(YR_COMPILER* compiler); YR_API void yr_compiler_set_callback( YR_COMPILER* compiler, YR_COMPILER_CALLBACK_FUNC callback, void* user_data); YR_API void yr_compiler_set_include_callback( YR_COMPILER* compiler, YR_COMPILER_INCLUDE_CALLBACK_FUNC include_callback, YR_COMPILER_INCLUDE_FREE_FUNC include_free, void* user_data); YR_API void yr_compiler_set_re_ast_callback( YR_COMPILER* compiler, YR_COMPILER_RE_AST_CALLBACK_FUNC re_ast_callback, void* user_data); YR_API void yr_compiler_set_atom_quality_table( YR_COMPILER* compiler, const void* table, int entries, unsigned char warning_threshold); YR_API int yr_compiler_load_atom_quality_table( YR_COMPILER* compiler, const char* filename, unsigned char warning_threshold); YR_API int yr_compiler_add_file( YR_COMPILER* compiler, FILE* rules_file, const char* namespace_, const char* file_name); YR_API int yr_compiler_add_fd( YR_COMPILER* compiler, YR_FILE_DESCRIPTOR rules_fd, const char* namespace_, const char* file_name); YR_API int yr_compiler_add_bytes( YR_COMPILER* compiler, const void* rules_data, size_t rules_size, const char* namespace_); YR_API int yr_compiler_add_string( YR_COMPILER* compiler, const char* rules_string, const char* namespace_); YR_API char* yr_compiler_get_error_message( YR_COMPILER* compiler, char* buffer, int buffer_size); YR_API char* yr_compiler_get_current_file_name(YR_COMPILER* compiler); YR_API int yr_compiler_define_integer_variable( YR_COMPILER* compiler, const char* identifier, int64_t value); YR_API int yr_compiler_define_boolean_variable( YR_COMPILER* compiler, const char* identifier, int value); YR_API int yr_compiler_define_float_variable( YR_COMPILER* compiler, const char* identifier, double value); YR_API int yr_compiler_define_string_variable( YR_COMPILER* compiler, const char* identifier, const char* value); YR_API int yr_compiler_get_rules(YR_COMPILER* compiler, YR_RULES** rules); #endif yara-4.5.3/libyara/include/yara/dex.h000066400000000000000000000054521501365277300174310ustar00rootroot00000000000000#ifndef _DEX_H #define _DEX_H #include #include #include #define DEX_FILE_MAGIC_035 "dex\n035\x00" #define DEX_FILE_MAGIC_036 "dex\n036\x00" #define DEX_FILE_MAGIC_037 "dex\n037\x00" #define DEX_FILE_MAGIC_038 "dex\n038\x00" #define DEX_FILE_MAGIC_039 "dex\n039\x00" #pragma pack(push, 1) typedef struct { uint8_t magic[8]; uint32_t checksum; uint8_t signature[20]; uint32_t file_size; uint32_t header_size; uint32_t endian_tag; uint32_t link_size; uint32_t link_offset; uint32_t map_offset; uint32_t string_ids_size; uint32_t string_ids_offset; uint32_t type_ids_size; uint32_t type_ids_offset; uint32_t proto_ids_size; uint32_t proto_ids_offset; uint32_t field_ids_size; uint32_t field_ids_offset; uint32_t method_ids_size; uint32_t method_ids_offset; uint32_t class_defs_size; uint32_t class_defs_offset; uint32_t data_size; uint32_t data_offset; } dex_header_t; typedef struct { uint32_t string_data_offset; } string_id_item_t; typedef struct { uint32_t utf16_size; } string_data_item_t; typedef struct { uint32_t descriptor_idx; } type_id_item_t; typedef struct { uint32_t shorty_idx; uint32_t return_type_idx; uint32_t parameters_offset; } proto_id_item_t; typedef struct { uint16_t class_idx; uint16_t type_idx; uint32_t name_idx; } field_id_item_t; typedef struct { uint16_t class_idx; uint16_t proto_idx; uint32_t name_idx; } method_id_item_t; typedef struct { uint32_t class_idx; uint32_t access_flags; uint32_t super_class_idx; uint32_t interfaces_offset; uint32_t source_file_idx; uint32_t annotations_offset; uint32_t class_data_offset; uint32_t static_values_offset; } class_id_item_t; typedef struct { uint32_t static_fields_size; uint32_t instance_fields_size; uint32_t direct_methods_size; uint32_t virtual_methods_size; } class_data_item_t; typedef struct { uint32_t field_idx_diff; uint32_t access_flags; } encoded_field_t; typedef struct { uint32_t method_idx_diff; uint32_t access_flags; uint32_t code_off; } encoded_method_t; typedef struct { uint16_t registers_size; uint16_t ins_size; uint16_t outs_size; uint16_t tries_size; uint32_t debug_info_off; uint32_t insns_size; } code_item_t; typedef struct { uint16_t type; uint16_t unused; uint32_t size; uint32_t offset; } map_item_t; typedef struct _DEX { const uint8_t* data; size_t data_size; dex_header_t* header; YR_OBJECT* object; } DEX; #define fits_in_dex(dex, pointer, size) \ ((size_t) size <= dex->data_size && (uint8_t*) (pointer) >= dex->data && \ (uint8_t*) (pointer) <= dex->data + dex->data_size - size) #define struct_fits_in_dex(dex, pointer, struct_type) \ fits_in_dex(dex, pointer, sizeof(struct_type)) #pragma pack(pop) #endif yara-4.5.3/libyara/include/yara/dotnet.h000066400000000000000000000317311501365277300201450ustar00rootroot00000000000000#ifndef YR_DOTNET_H #define YR_DOTNET_H #include #include #include #pragma pack(push, 1) // // CLI header. // ECMA-335 Section II.25.3.3 // typedef struct _CLI_HEADER { DWORD Size; // Called "Cb" in documentation. WORD MajorRuntimeVersion; WORD MinorRuntimeVersion; IMAGE_DATA_DIRECTORY MetaData; DWORD Flags; DWORD EntryPointToken; IMAGE_DATA_DIRECTORY Resources; IMAGE_DATA_DIRECTORY StrongNameSignature; ULONGLONG CodeManagerTable; IMAGE_DATA_DIRECTORY VTableFixups; ULONGLONG ExportAddressTableJumps; ULONGLONG ManagedNativeHeader; } CLI_HEADER, *PCLI_HEADER; #define NET_METADATA_MAGIC 0x424a5342 // // CLI MetaData // ECMA-335 Section II.24.2.1 // // Note: This is only part of the struct, as the rest of it is variable length. // typedef struct _NET_METADATA { DWORD Magic; WORD MajorVersion; WORD MinorVersion; DWORD Reserved; DWORD Length; char Version[0]; } NET_METADATA, *PNET_METADATA; #define DOTNET_STREAM_NAME_SIZE 32 // // CLI Stream Header // ECMA-335 Section II.24.2.2 // typedef struct _STREAM_HEADER { DWORD Offset; DWORD Size; char Name[0]; } STREAM_HEADER, *PSTREAM_HEADER; // // CLI #~ Stream Header // ECMA-335 Section II.24.2.6 // typedef struct _TILDE_HEADER { DWORD Reserved1; BYTE MajorVersion; BYTE MinorVersion; BYTE HeapSizes; BYTE Reserved2; ULONGLONG Valid; ULONGLONG Sorted; } TILDE_HEADER, *PTILDE_HEADER; // flag in HeapSizes that denotes extra 4 bytes after Rows #define HEAP_EXTRA_DATA 0x40 #define SIG_FLAG_GENERIC 0x10 // These are the bit positions in Valid which will be set if the table // exists. #define BIT_MODULE 0x00 #define BIT_TYPEREF 0x01 #define BIT_TYPEDEF 0x02 #define BIT_FIELDPTR 0x03 // Not documented in ECMA-335 #define BIT_FIELD 0x04 #define BIT_METHODDEFPTR 0x05 // Not documented in ECMA-335 #define BIT_METHODDEF 0x06 #define BIT_PARAMPTR 0x07 // Not documented in ECMA-335 #define BIT_PARAM 0x08 #define BIT_INTERFACEIMPL 0x09 #define BIT_MEMBERREF 0x0A #define BIT_CONSTANT 0x0B #define BIT_CUSTOMATTRIBUTE 0x0C #define BIT_FIELDMARSHAL 0x0D #define BIT_DECLSECURITY 0x0E #define BIT_CLASSLAYOUT 0x0F #define BIT_FIELDLAYOUT 0x10 #define BIT_STANDALONESIG 0x11 #define BIT_EVENTMAP 0x12 #define BIT_EVENTPTR 0x13 // Not documented in ECMA-335 #define BIT_EVENT 0x14 #define BIT_PROPERTYMAP 0x15 #define BIT_PROPERTYPTR 0x16 // Not documented in ECMA-335 #define BIT_PROPERTY 0x17 #define BIT_METHODSEMANTICS 0x18 #define BIT_METHODIMPL 0x19 #define BIT_MODULEREF 0x1A #define BIT_TYPESPEC 0x1B #define BIT_IMPLMAP 0x1C #define BIT_FIELDRVA 0x1D #define BIT_ENCLOG 0x1E // Not documented in ECMA-335 #define BIT_ENCMAP 0x1F // Not documented in ECMA-335 #define BIT_ASSEMBLY 0x20 #define BIT_ASSEMBLYPROCESSOR 0x21 #define BIT_ASSEMBLYOS 0x22 #define BIT_ASSEMBLYREF 0x23 #define BIT_ASSEMBLYREFPROCESSOR 0x24 #define BIT_ASSEMBLYREFOS 0x25 #define BIT_FILE 0x26 #define BIT_EXPORTEDTYPE 0x27 #define BIT_MANIFESTRESOURCE 0x28 #define BIT_NESTEDCLASS 0x29 #define BIT_GENERICPARAM 0x2A #define BIT_METHODSPEC 0x2B #define BIT_GENERICPARAMCONSTRAINT 0x2C // These are not documented in ECMA-335 nor is it clear what the format is. // They are for debugging information as far as I can tell. //#define BIT_DOCUMENT 0x30 //#define BIT_METHODDEBUGINFORMATION 0x31 //#define BIT_LOCALSCOPE 0x32 //#define BIT_LOCALVARIABLE 0x33 //#define BIT_LOCALCONSTANT 0x34 //#define BIT_IMPORTSCOPE 0x35 //#define BIT_STATEMACHINEMETHOD 0x36 // The string length of a typelib attribute is at most 0xFF. #define MAX_TYPELIB_SIZE 0xFF // Flags and Masks for .NET tables #define TYPE_ATTR_CLASS_SEMANTIC_MASK 0x20 #define TYPE_ATTR_CLASS 0x0 #define TYPE_ATTR_INTERFACE 0x20 #define TYPE_ATTR_VISIBILITY_MASK 0x7 #define TYPE_ATTR_NOT_PUBLIC 0x0 #define TYPE_ATTR_PUBLIC 0x1 #define TYPE_ATTR_NESTED_PUBLIC 0x2 #define TYPE_ATTR_NESTED_PRIVATE 0x3 #define TYPE_ATTR_NESTED_FAMILY 0x4 #define TYPE_ATTR_NESTED_ASSEMBLY 0x5 #define TYPE_ATTR_NESTED_FAM_AND_ASSEM 0x6 #define TYPE_ATTR_NESTED_FAM_OR_ASSEM 0x7 #define TYPE_ATTR_ABSTRACT 0x80 #define TYPE_ATTR_SEALED 0x100 #define METHOD_ATTR_ACCESS_MASK 0x7 #define METHOD_ATTR_PRIVATE 0x1 #define METHOD_ATTR_FAM_AND_ASSEM 0x2 #define METHOD_ATTR_ASSEM 0x3 #define METHOD_ATTR_FAMILY 0x4 #define METHOD_ATTR_FAM_OR_ASSEM 0x5 #define METHOD_ATTR_PUBLIC 0x6 #define METHOD_ATTR_STATIC 0x10 #define METHOD_ATTR_FINAL 0x20 #define METHOD_ATTR_VIRTUAL 0x40 #define METHOD_ATTR_ABSTRACT 0x400 // Element types ECMA-335 Section II.23.1.16 #define TYPE_END 0x0 #define TYPE_VOID 0x1 #define TYPE_BOOL 0x2 #define TYPE_CHAR 0x3 #define TYPE_I1 0x4 #define TYPE_U1 0x5 #define TYPE_I2 0x6 #define TYPE_U2 0x7 #define TYPE_I4 0x8 #define TYPE_U4 0x9 #define TYPE_I8 0xa #define TYPE_U8 0xb #define TYPE_R4 0xc #define TYPE_R8 0xd #define TYPE_STRING 0xe #define TYPE_PTR 0xf #define TYPE_BYREF 0x10 #define TYPE_VALUETYPE 0x11 #define TYPE_CLASS 0x12 #define TYPE_VAR 0x13 #define TYPE_ARRAY 0x14 #define TYPE_GENERICINST 0x15 #define TYPE_TYPEDREF 0x16 #define TYPE_I 0x18 #define TYPE_U 0x19 #define TYPE_FNPTR 0x1b #define TYPE_OBJECT 0x1c #define TYPE_SZARRAY 0x1d #define TYPE_MVAR 0x1e #define TYPE_CMOD_REQD 0x1f #define TYPE_CMOD_OPT 0x20 #define TYPE_INTERNAL 0x21 #define TYPE_MODIFIER 0x40 #define TYPE_SENTINEL 0x41 #define TYPE_PINNED 0x45 // Sane boundaries for invalid files #define MAX_ARRAY_RANK 50 #define MAX_PARAM_COUNT 2000 #define MAX_GEN_PARAM_COUNT 1000 #define MAX_METHOD_COUNT 20000 #define MAX_STRING_LENGTH 10000 // Sanity check for loops in type parser #define MAX_TYPE_DEPTH 0x10 #define MAX_NAMESPACE_DEPTH 0x0a // // Module table // ECMA-335 Section II.22.30 // typedef struct _MODULE_TABLE { WORD Generation; union { WORD Name_Short; DWORD Name_Long; } Name; union { WORD Mvid_Short; DWORD Mvid_Long; } Mvid; union { WORD EncId_Short; DWORD EncId_Long; } EncId; union { WORD EncBaseId_Short; DWORD EncBaseId_Long; } EncBaseId; } MODULE_TABLE, *PMODULE_TABLE; // // Assembly Table // ECMA-335 Section II.22.2 // typedef struct _ASSEMBLY_TABLE { DWORD HashAlgId; WORD MajorVersion; WORD MinorVersion; WORD BuildNumber; WORD RevisionNumber; DWORD Flags; union { WORD PublicKey_Short; DWORD PublicKey_Long; } PublicKey; union { WORD Name_Short; DWORD Name_Long; } Name; } ASSEMBLY_TABLE, *PASSEMBLY_TABLE; // // Assembly Reference Table // ECMA-335 Section II.22.5 // typedef struct _ASSEMBLYREF_TABLE { WORD MajorVersion; WORD MinorVersion; WORD BuildNumber; WORD RevisionNumber; DWORD Flags; union { WORD PublicKeyOrToken_Short; DWORD PublicKeyOrToken_Long; } PublicKeyOrToken; union { WORD Name_Short; DWORD Name_Long; } Name; } ASSEMBLYREF_TABLE, *PASSEMBLYREF_TABLE; // // Manifest Resource Table // ECMA-335 Section II.22.24 // typedef struct _MANIFESTRESOURCE_TABLE { DWORD Offset; DWORD Flags; union { WORD Name_Short; DWORD Name_Long; } Name; union { WORD Implementation_Short; DWORD Implementation_Long; } Implementation; } MANIFESTRESOURCE_TABLE, *PMANIFESTRESOURCE_TABLE; // // ModuleRef Table // ECMA-335 Section II.22.31 // // This is a short table, but necessary because the field size can change. // typedef struct _MODULEREF_TABLE { union { WORD Name_Short; DWORD Name_Long; } Name; } MODULEREF_TABLE, *PMODULEREF_TABLE; // // FieldRVA Table // ECMA-335 Section II.22.18 // typedef struct _FIELDRVA_TABLE { DWORD RVA; union { WORD Field_Short; DWORD Field_LONG; } Field; } FIELDRVA_TABLE, *PFIELDRVA_TABLE; // // CustomAttribute Table // ECMA-335 Section II.22.10 // typedef struct _CUSTOMATTRIBUTE_TABLE { union { WORD Parent_Short; DWORD Parent_Long; } Parent; union { WORD Type_Short; DWORD Type_Long; } Type; union { WORD Value_Short; DWORD Value_Long; } Value; } CUSTOMATTRIBUTE_TABLE, *PCUSTOMATTRIBUTE_TABLE; // // Constant TAble // ECMA-335 Section II.22.9 // typedef struct _CONSTANT_TABLE { WORD Type; union { WORD Parent_Short; DWORD Parent_Long; } Parent; union { WORD Value_Short; DWORD Value_Long; } Value; } CONSTANT_TABLE, *PCONSTANT_TABLE; // ECMA 335 - II.22.37 typedef struct _TYPEDEF_ROW { uint32_t Flags; uint32_t Name; uint32_t Namespace; uint32_t Extends; uint32_t Field; uint32_t Method; } TYPEDEF_ROW, *PTYPEDEF_ROW; // ECMA 335 - II.22.38 typedef struct _TYPEREF_ROW { uint32_t ResolutionScope; uint32_t Name; uint32_t Namespace; } TYPEREF_ROW, *PTYPEREF_ROW; // ECMA 335 - II.22.39 typedef struct _TYPESPEC_ROW { uint32_t Signature; } TYPESPEC_ROW, *PTYPESPEC_ROW; // ECMA 335 - II.22.23 typedef struct _INTERFACEIMPL_ROW { uint32_t Class; uint32_t Interface; } INTERFACEIMPL_ROW, *PINTERFACEIMPL_ROW; // ECMA 335 II.22.26 typedef struct _METHODDEF_ROW { uint32_t Rva; uint16_t ImplFlags; uint16_t Flags; uint32_t Name; uint32_t Signature; uint32_t ParamList; } METHODDEF_ROW, *PMETHODDEF_ROW; // ECMA 335 II.22.33 typedef struct _PARAM_ROW { uint16_t Flags; uint16_t Sequence; uint32_t Name; } PARAM_ROW, *PPARAM_ROW; // ECMA 335 II.22.20 typedef struct _GENERICPARAM_ROW { uint16_t Number; uint16_t Flags; uint32_t Owner; uint32_t Name; } GENERICPARAM_ROW, *PGENERICPARAM_ROW; // ECMA 335 II.22.32 typedef struct _NESTEDCLASS_ROW { uint32_t NestedClass; uint32_t EnclosingClass; } NESTEDCLASS_ROW, *PNESTEDCLASS_ROW; // For easy passing of gen param collection typedef struct _GENERIC_PARAMETERS { char **names; uint32_t len; } GENERIC_PARAMETERS, *PGENERIC_PARAMETERS; // Used to return offsets to the various headers. typedef struct _STREAMS { int64_t metadata_root; // base from which are stream offsets relative PSTREAM_HEADER guid; PSTREAM_HEADER tilde; PSTREAM_HEADER string; PSTREAM_HEADER blob; PSTREAM_HEADER us; } STREAMS, *PSTREAMS; // Used to return the value of parsing a #US or #Blob entry. // ECMA-335 Section II.24.2.4 typedef struct _BLOB_PARSE_RESULT { uint8_t size; // Number of bytes parsed. This is the new offset. uint32_t length; // Value of the bytes parsed. This is the blob length. } BLOB_PARSE_RESULT, *PBLOB_PARSE_RESULT; typedef struct _TABLE_INFO { uint8_t *Offset; uint32_t RowCount; uint32_t RowSize; } TABLE_INFO, *PTABLE_INFO; // Structure that stores table information for parsing typedef struct _TABLES { TABLE_INFO typedef_; TABLE_INFO typespec; TABLE_INFO typeref; TABLE_INFO methoddef; TABLE_INFO param; TABLE_INFO module; TABLE_INFO moduleref; TABLE_INFO assembly; TABLE_INFO assemblyref; TABLE_INFO intefaceimpl; TABLE_INFO genericparam; TABLE_INFO nestedclass; } TABLES, *PTABLES; // Used to store the number of rows of each table. typedef struct _ROWS { uint32_t module; uint32_t moduleref; uint32_t assemblyref; uint32_t typeref; uint32_t methoddef; uint32_t memberref; uint32_t typedef_; uint32_t typespec; uint32_t field; uint32_t param; uint32_t property; uint32_t interfaceimpl; uint32_t event; uint32_t standalonesig; uint32_t assembly; uint32_t file; uint32_t exportedtype; uint32_t manifestresource; uint32_t genericparam; uint32_t genericparamconstraint; uint32_t methodspec; uint32_t assemblyrefprocessor; } ROWS, *PROWS; // Used to store the index sizes for the various tables. typedef struct _INDEX_SIZES { uint8_t string; uint8_t guid; uint8_t blob; uint8_t field; uint8_t methoddef; uint8_t methodspec; uint8_t memberref; uint8_t param; uint8_t event; uint8_t typedef_; uint8_t typeref; uint8_t typespec; uint8_t interfaceimpl; uint8_t property; uint8_t moduleref; uint8_t module; uint8_t assemblyrefprocessor; uint8_t assemblyref; uint8_t assembly; uint8_t genericparam; } INDEX_SIZES, *PINDEX_SIZES; typedef struct _CLASS_CONTEXT { PE* pe; TABLES* tables; INDEX_SIZES* index_sizes; const uint8_t* str_heap; uint32_t str_size; const uint8_t* blob_heap; uint32_t blob_size; } CLASS_CONTEXT, *PCLASS_CONTEXT; typedef struct _PARAMETERS { char* name; char* type; bool alloc; // if name is allocated and needs to be free } PARAMETERS, *PPARAMETERS; #pragma pack(pop) #endif yara-4.5.3/libyara/include/yara/elf.h000066400000000000000000000246041501365277300174170ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _ELF_H #define _ELF_H #include // 32-bit ELF base types typedef uint32_t elf32_addr_t; typedef uint16_t elf32_half_t; typedef uint32_t elf32_off_t; typedef uint32_t elf32_word_t; // 64-bit ELF base types typedef uint64_t elf64_addr_t; typedef uint16_t elf64_half_t; typedef uint64_t elf64_off_t; typedef uint32_t elf64_word_t; typedef uint64_t elf64_xword_t; #define ELF_MAGIC 0x464C457F #define ELF_ET_NONE 0x0000 // no type #define ELF_ET_REL 0x0001 // relocatable #define ELF_ET_EXEC 0x0002 // executable #define ELF_ET_DYN 0x0003 // Shared-Object-File #define ELF_ET_CORE 0x0004 // Corefile #define ELF_ET_LOPROC 0xFF00 // Processor-specific #define ELF_ET_HIPROC 0x00FF // Processor-specific #define ELF_EM_NONE 0x0000 // no type #define ELF_EM_M32 0x0001 // AT&T WE 32100 #define ELF_EM_SPARC 0x0002 // SPARC #define ELF_EM_386 0x0003 // Intel 80386 #define ELF_EM_68K 0x0004 // Motorola 68000 #define ELF_EM_88K 0x0005 // Motorola 88000 #define ELF_EM_860 0x0007 // Intel 80860 #define ELF_EM_MIPS 0x0008 // MIPS I Architecture #define ELF_EM_MIPS_RS3_LE 0x000A // MIPS RS3000 Little-endian #define ELF_EM_PPC 0x0014 // PowerPC #define ELF_EM_PPC64 0x0015 // 64-bit PowerPC #define ELF_EM_ARM 0x0028 // ARM #define ELF_EM_X86_64 0x003E // AMD/Intel x86_64 #define ELF_EM_AARCH64 0x00B7 // 64-bit ARM #define ELF_CLASS_NONE 0x0000 #define ELF_CLASS_32 0x0001 // 32bit file #define ELF_CLASS_64 0x0002 // 64bit file #define ELF_DATA_NONE 0x0000 #define ELF_DATA_2LSB 0x0001 #define ELF_DATA_2MSB 0x002 #define ELF_SHT_NULL 0 // Section header table entry unused #define ELF_SHT_PROGBITS 1 // Program data #define ELF_SHT_SYMTAB 2 // Symbol table #define ELF_SHT_STRTAB 3 // String table #define ELF_SHT_RELA 4 // Relocation entries with addends #define ELF_SHT_HASH 5 // Symbol hash table #define ELF_SHT_DYNAMIC 6 // Dynamic linking information #define ELF_SHT_NOTE 7 // Notes #define ELF_SHT_NOBITS 8 // Program space with no data (bss) #define ELF_SHT_REL 9 // Relocation entries, no addends #define ELF_SHT_SHLIB 10 // Reserved #define ELF_SHT_DYNSYM 11 // Dynamic linker symbol table #define ELF_SHT_NUM 12 // Number of defined types #define ELF_SHF_WRITE 0x1 // Section is writable #define ELF_SHF_ALLOC 0x2 // Section is present during execution #define ELF_SHF_EXECINSTR 0x4 // Section contains executable instructions #define ELF_SHN_LORESERVE 0xFF00 #define ELF_PT_NULL 0 // The array element is unused #define ELF_PT_LOAD 1 // Loadable segment #define ELF_PT_DYNAMIC 2 // Segment contains dynamic linking info #define ELF_PT_INTERP 3 // Contains interpreter pathname #define ELF_PT_NOTE 4 // Location & size of auxiliary info #define ELF_PT_SHLIB 5 // Reserved, unspecified semantics #define ELF_PT_PHDR 6 // Location and size of program header table #define ELF_PT_TLS 7 // Thread-Local Storage #define ELF_PT_GNU_EH_FRAME 0x6474e550 #define ELF_PT_GNU_STACK 0x6474e551 #define ELF_DT_NULL 0 // End of the dynamic entries #define ELF_DT_NEEDED 1 // Name of needed library #define ELF_DT_PLTRELSZ 2 // Size in bytes of PLT relocs #define ELF_DT_PLTGOT 3 // Processor defined value */ #define ELF_DT_HASH 4 // Address of symbol hash table #define ELF_DT_STRTAB 5 // Address of string table #define ELF_DT_SYMTAB 6 // Address of symbol table #define ELF_DT_RELA 7 // Address of Rela relocs #define ELF_DT_RELASZ 8 // Total size of Rela relocs #define ELF_DT_RELAENT 9 // Size of one Rela reloc #define ELF_DT_STRSZ 10 // Size of string table #define ELF_DT_SYMENT 11 // Size of one symbol table entry #define ELF_DT_INIT 12 // Address of init function #define ELF_DT_FINI 13 // Address of termination function #define ELF_DT_SONAME 14 // Name of shared object #define ELF_DT_RPATH 15 // Library search path (deprecated) #define ELF_DT_SYMBOLIC 16 // Start symbol search here #define ELF_DT_REL 17 // Address of Rel relocs #define ELF_DT_RELSZ 18 // Total size of Rel relocs #define ELF_DT_RELENT 19 // Size of one Rel reloc #define ELF_DT_PLTREL 20 // Type of reloc in PLT #define ELF_DT_DEBUG 21 // For debugging; unspecified #define ELF_DT_TEXTREL 22 // Reloc might modify .text #define ELF_DT_JMPREL 23 // Address of PLT relocs #define ELF_DT_BIND_NOW 24 // Process relocations of object #define ELF_DT_INIT_ARRAY 25 // Array with addresses of init fct #define ELF_DT_FINI_ARRAY 26 // Array with addresses of fini fct #define ELF_DT_INIT_ARRAYSZ 27 // Size in bytes of DT_INIT_ARRAY #define ELF_DT_FINI_ARRAYSZ 28 // Size in bytes of DT_FINI_ARRAY #define ELF_DT_RUNPATH 29 // Library search path #define ELF_DT_FLAGS 30 // Flags for the object being loaded #define ELF_DT_ENCODING 32 // Start of encoded range #define ELF_STT_NOTYPE 0 // Symbol type is unspecified #define ELF_STT_OBJECT 1 // Symbol is a data object #define ELF_STT_FUNC 2 // Symbol is a code object #define ELF_STT_SECTION 3 // Symbol associated with a section #define ELF_STT_FILE 4 // Symbol's name is file name #define ELF_STT_COMMON 5 // Symbol is a common data object #define ELF_STT_TLS 6 // Symbol is thread-local data object #define ELF_STV_DEFAULT 0 // Visibility by binding #define ELF_STV_INTERNAL 1 // Reserved #define ELF_STV_HIDDEN 2 // Not visible to other components #define ELF_STV_PROTECTED 3 // Visible in other but cannot be preempted. #define ELF_STB_LOCAL 0 // Local symbol #define ELF_STB_GLOBAL 1 // Global symbol #define ELF_STB_WEAK 2 // Weak symbol #define ELF_PF_X 0x1 // Segment is executable #define ELF_PF_W 0x2 // Segment is writable #define ELF_PF_R 0x4 // Segment is readable #define ELF_PN_XNUM 0xffff #define ELF_SHN_UNDEF 0 // Missing, undefined section index #define ELF_SHN_ABS 0xFFF1 // Absolute references, not affected by relocs #define ELF_SHN_COMMON 0xFFF2 // Symbols relative to this are common #pragma pack(push, 1) typedef struct { uint32_t magic; uint8_t _class; uint8_t data; uint8_t version; uint8_t pad[8]; uint8_t nident; } elf_ident_t; typedef struct { elf_ident_t ident; elf32_half_t type; elf32_half_t machine; elf32_word_t version; elf32_addr_t entry; elf32_off_t ph_offset; elf32_off_t sh_offset; elf32_word_t flags; elf32_half_t header_size; elf32_half_t ph_entry_size; elf32_half_t ph_entry_count; elf32_half_t sh_entry_size; elf32_half_t sh_entry_count; elf32_half_t sh_str_table_index; } elf32_header_t; typedef struct { elf_ident_t ident; elf64_half_t type; elf64_half_t machine; elf64_word_t version; elf64_addr_t entry; elf64_off_t ph_offset; elf64_off_t sh_offset; elf64_word_t flags; elf64_half_t header_size; elf64_half_t ph_entry_size; elf64_half_t ph_entry_count; elf64_half_t sh_entry_size; elf64_half_t sh_entry_count; elf64_half_t sh_str_table_index; } elf64_header_t; typedef struct { elf32_word_t type; elf32_off_t offset; elf32_addr_t virt_addr; elf32_addr_t phys_addr; elf32_word_t file_size; elf32_word_t mem_size; elf32_word_t flags; elf32_word_t alignment; } elf32_program_header_t; typedef struct { elf64_word_t type; elf64_word_t flags; elf64_off_t offset; elf64_addr_t virt_addr; elf64_addr_t phys_addr; elf64_xword_t file_size; elf64_xword_t mem_size; elf64_xword_t alignment; } elf64_program_header_t; typedef struct { elf32_word_t name; elf32_word_t type; elf32_word_t flags; elf32_addr_t addr; elf32_off_t offset; elf32_word_t size; elf32_word_t link; elf32_word_t info; elf32_word_t align; elf32_word_t entry_size; } elf32_section_header_t; typedef struct { elf64_word_t name; elf64_word_t type; elf64_xword_t flags; elf64_addr_t addr; elf64_off_t offset; elf64_xword_t size; elf64_word_t link; elf64_word_t info; elf64_xword_t align; elf64_xword_t entry_size; } elf64_section_header_t; typedef struct { elf32_word_t tag; elf32_word_t val; } elf32_dyn_t; typedef struct { elf64_xword_t tag; elf64_xword_t val; } elf64_dyn_t; typedef struct { elf32_word_t name; elf32_addr_t value; elf32_word_t size; unsigned char info; unsigned char other; elf32_half_t shndx; } elf32_sym_t; typedef struct { elf32_word_t name; unsigned char info; unsigned char other; elf32_half_t shndx; elf64_addr_t value; elf64_xword_t size; } elf64_sym_t; #pragma pack(pop) #endif yara-4.5.3/libyara/include/yara/elf_utils.h000066400000000000000000000010171501365277300206300ustar00rootroot00000000000000#ifndef YR_ELF_UTILS_H #define YR_ELF_UTILS_H #include typedef struct _ELF_SYMBOL { char *name; int value; int size; int type; int bind; int shndx; int visibility; struct _ELF_SYMBOL *next; // Next symbol in the list } ELF_SYMBOL; // Linked list of symbols typedef struct _ELF_SYMBOL_LIST { int count; ELF_SYMBOL *symbols; } ELF_SYMBOL_LIST; typedef struct _ELF { ELF_SYMBOL_LIST *symtab; ELF_SYMBOL_LIST *dynsym; char *telfhash; char *import_hash; } ELF; #endif //YR_ELF_UTILS_H yara-4.5.3/libyara/include/yara/endian.h000066400000000000000000000056071501365277300201110ustar00rootroot00000000000000/* Copyright (c) 2016. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_ENDIAN_H #define YR_ENDIAN_H #include #if defined(__has_builtin) #if __has_builtin(__builtin_bswap16) #define yr_bswap16(x) __builtin_bswap16(x) #endif #endif #if !defined(yr_bswap16) && defined(_MSC_VER) #define yr_bswap16(x) _byteswap_ushort(x) #endif #if !defined(yr_bswap16) uint16_t _yr_bswap16(uint16_t x); #define yr_bswap16(x) _yr_bswap16(x) #endif #if defined(__has_builtin) #if __has_builtin(__builtin_bswap32) #define yr_bswap32(x) __builtin_bswap32(x) #endif #endif #if !defined(yr_bswap32) && defined(_MSC_VER) #define yr_bswap32(x) _byteswap_ulong(x) #endif #if !defined(yr_bswap32) uint32_t _yr_bswap32(uint32_t x); #define yr_bswap32(x) _yr_bswap32(x) #endif #if defined(__has_builtin) #if __has_builtin(__builtin_bswap64) #define yr_bswap64(x) __builtin_bswap64(x) #endif #endif #if !defined(yr_bswap64) && defined(_MSC_VER) #define yr_bswap64(x) _byteswap_uint64(x) #endif #if !defined(yr_bswap64) uint64_t _yr_bswap64(uint64_t x); #define yr_bswap64(x) _yr_bswap64(x) #endif #if defined(WORDS_BIGENDIAN) #define yr_le16toh(x) yr_bswap16(x) #define yr_le32toh(x) yr_bswap32(x) #define yr_le64toh(x) yr_bswap64(x) #define yr_be16toh(x) (x) #define yr_be32toh(x) (x) #define yr_be64toh(x) (x) #else #define yr_le16toh(x) (x) #define yr_le32toh(x) (x) #define yr_le64toh(x) (x) #define yr_be16toh(x) yr_bswap16(x) #define yr_be32toh(x) yr_bswap32(x) #define yr_be64toh(x) yr_bswap64(x) #endif #endif yara-4.5.3/libyara/include/yara/error.h000066400000000000000000000156441501365277300200060ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_ERROR_H #define YR_ERROR_H #include #if defined(_WIN32) || defined(__CYGWIN__) #include #endif #ifndef ERROR_SUCCESS #define ERROR_SUCCESS 0 #endif // ERROR_INSUFICIENT_MEMORY is misspelled but it's kept for backward // compatibility, as some other programs can be using it in this form. #define ERROR_INSUFICIENT_MEMORY 1 #define ERROR_INSUFFICIENT_MEMORY 1 #define ERROR_COULD_NOT_ATTACH_TO_PROCESS 2 #define ERROR_COULD_NOT_OPEN_FILE 3 #define ERROR_COULD_NOT_MAP_FILE 4 #define ERROR_INVALID_FILE 6 #define ERROR_CORRUPT_FILE 7 #define ERROR_UNSUPPORTED_FILE_VERSION 8 #define ERROR_INVALID_REGULAR_EXPRESSION 9 #define ERROR_INVALID_HEX_STRING 10 #define ERROR_SYNTAX_ERROR 11 #define ERROR_LOOP_NESTING_LIMIT_EXCEEDED 12 #define ERROR_DUPLICATED_LOOP_IDENTIFIER 13 #define ERROR_DUPLICATED_IDENTIFIER 14 #define ERROR_DUPLICATED_TAG_IDENTIFIER 15 #define ERROR_DUPLICATED_META_IDENTIFIER 16 #define ERROR_DUPLICATED_STRING_IDENTIFIER 17 #define ERROR_UNREFERENCED_STRING 18 #define ERROR_UNDEFINED_STRING 19 #define ERROR_UNDEFINED_IDENTIFIER 20 #define ERROR_MISPLACED_ANONYMOUS_STRING 21 #define ERROR_INCLUDES_CIRCULAR_REFERENCE 22 #define ERROR_INCLUDE_DEPTH_EXCEEDED 23 #define ERROR_WRONG_TYPE 24 #define ERROR_EXEC_STACK_OVERFLOW 25 #define ERROR_SCAN_TIMEOUT 26 // Unused. Keep here for compatibility with legacy code that may be using // this constant. #define ERROR_TOO_MANY_SCAN_THREADS 27 #define ERROR_CALLBACK_ERROR 28 #define ERROR_INVALID_ARGUMENT 29 #define ERROR_TOO_MANY_MATCHES 30 #define ERROR_INTERNAL_FATAL_ERROR 31 #define ERROR_NESTED_FOR_OF_LOOP 32 #define ERROR_INVALID_FIELD_NAME 33 #define ERROR_UNKNOWN_MODULE 34 #define ERROR_NOT_A_STRUCTURE 35 #define ERROR_NOT_INDEXABLE 36 #define ERROR_NOT_A_FUNCTION 37 #define ERROR_INVALID_FORMAT 38 #define ERROR_TOO_MANY_ARGUMENTS 39 #define ERROR_WRONG_ARGUMENTS 40 #define ERROR_WRONG_RETURN_TYPE 41 #define ERROR_DUPLICATED_STRUCTURE_MEMBER 42 #define ERROR_EMPTY_STRING 43 #define ERROR_DIVISION_BY_ZERO 44 #define ERROR_REGULAR_EXPRESSION_TOO_LARGE 45 #define ERROR_TOO_MANY_RE_FIBERS 46 #define ERROR_COULD_NOT_READ_PROCESS_MEMORY 47 #define ERROR_INVALID_EXTERNAL_VARIABLE_TYPE 48 #define ERROR_REGULAR_EXPRESSION_TOO_COMPLEX 49 #define ERROR_INVALID_MODULE_NAME 50 #define ERROR_TOO_MANY_STRINGS 51 #define ERROR_INTEGER_OVERFLOW 52 #define ERROR_CALLBACK_REQUIRED 53 #define ERROR_INVALID_OPERAND 54 #define ERROR_COULD_NOT_READ_FILE 55 #define ERROR_DUPLICATED_EXTERNAL_VARIABLE 56 #define ERROR_INVALID_MODULE_DATA 57 #define ERROR_WRITING_FILE 58 #define ERROR_INVALID_MODIFIER 59 #define ERROR_DUPLICATED_MODIFIER 60 #define ERROR_BLOCK_NOT_READY 61 #define ERROR_INVALID_PERCENTAGE 62 #define ERROR_IDENTIFIER_MATCHES_WILDCARD 63 #define ERROR_INVALID_VALUE 64 #define ERROR_TOO_SLOW_SCANNING 65 #define ERROR_UNKNOWN_ESCAPE_SEQUENCE 66 #define GOTO_EXIT_ON_ERROR(x) \ { \ result = (x); \ if (result != ERROR_SUCCESS) \ goto _exit; \ } #define GOTO_EXIT_ON_ERROR_WITH_CLEANUP(x, cleanup) \ { \ result = (x); \ if (result != ERROR_SUCCESS) \ { \ cleanup; \ goto _exit; \ } \ } #define FAIL_ON_ERROR(x) \ { \ int __error = (x); \ if (__error != ERROR_SUCCESS) \ return __error; \ } #define FAIL_ON_ERROR_WITH_CLEANUP(x, cleanup) \ { \ int __error = (x); \ if (__error != ERROR_SUCCESS) \ { \ cleanup; \ return __error; \ } \ } #define FAIL_ON_NULL_WITH_CLEANUP(x, cleanup) \ { \ if ((x) == NULL) \ { \ cleanup; \ return ERROR_INSUFFICIENT_MEMORY; \ } \ } #ifdef NDEBUG #define assertf(expr, msg, ...) ((void) 0) #else #define assertf(expr, msg, ...) \ if (!(expr)) \ { \ fprintf(stderr, "%s:%d: " msg "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ abort(); \ } #endif #endif yara-4.5.3/libyara/include/yara/exec.h000066400000000000000000000172221501365277300175730ustar00rootroot00000000000000/* Copyright (c) 2013-2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_EXEC_H #define YR_EXEC_H #include #include #include #include #define YR_UNDEFINED 0xFFFABADAFABADAFFLL #define IS_UNDEFINED(x) ((size_t)(x) == (size_t) YR_UNDEFINED) // Used to tell OP_OF and OP_OF_PERCENT what kind of set is being used. #define OF_STRING_SET 0 #define OF_RULE_SET 1 #define OP_ERROR 0 #define OP_HALT 255 #define OP_NOP 254 #define OP_AND 1 #define OP_OR 2 #define OP_NOT 3 #define OP_BITWISE_NOT 4 #define OP_BITWISE_AND 5 #define OP_BITWISE_OR 6 #define OP_BITWISE_XOR 7 #define OP_SHL 8 #define OP_SHR 9 #define OP_MOD 10 #define OP_INT_TO_DBL 11 #define OP_STR_TO_BOOL 12 #define OP_PUSH 13 #define OP_POP 14 #define OP_CALL 15 #define OP_OBJ_LOAD 16 #define OP_OBJ_VALUE 17 #define OP_OBJ_FIELD 18 #define OP_INDEX_ARRAY 19 #define OP_COUNT 20 #define OP_LENGTH 21 #define OP_FOUND 22 #define OP_FOUND_AT 23 #define OP_FOUND_IN 24 #define OP_OFFSET 25 #define OP_OF 26 #define OP_PUSH_RULE 27 #define OP_INIT_RULE 28 #define OP_MATCH_RULE 29 #define OP_INCR_M 30 #define OP_CLEAR_M 31 #define OP_ADD_M 32 #define OP_POP_M 33 #define OP_PUSH_M 34 #define OP_SET_M 35 #define OP_SWAPUNDEF 36 #define OP_FILESIZE 37 #define OP_ENTRYPOINT 38 #define OP_UNUSED 39 #define OP_MATCHES 40 #define OP_IMPORT 41 #define OP_LOOKUP_DICT 42 #define OP_JUNDEF 43 /* Not used */ #define OP_JUNDEF_P 44 #define OP_JNUNDEF 45 #define OP_JNUNDEF_P 46 /* Not used */ #define OP_JFALSE 47 #define OP_JFALSE_P 48 #define OP_JTRUE 49 #define OP_JTRUE_P 50 #define OP_JL_P 51 #define OP_JLE_P 52 #define OP_ITER_NEXT 53 #define OP_ITER_START_ARRAY 54 #define OP_ITER_START_DICT 55 #define OP_ITER_START_INT_RANGE 56 #define OP_ITER_START_INT_ENUM 57 #define OP_ITER_START_STRING_SET 58 #define OP_ITER_CONDITION 59 #define OP_ITER_END 60 #define OP_JZ 61 #define OP_JZ_P 62 #define OP_PUSH_8 63 #define OP_PUSH_16 64 #define OP_PUSH_32 65 #define OP_PUSH_U 66 #define OP_CONTAINS 67 #define OP_STARTSWITH 68 #define OP_ENDSWITH 69 #define OP_ICONTAINS 70 #define OP_ISTARTSWITH 71 #define OP_IENDSWITH 72 #define OP_IEQUALS 73 #define OP_OF_PERCENT 74 #define OP_OF_FOUND_IN 75 #define OP_COUNT_IN 76 #define OP_DEFINED 77 #define OP_ITER_START_TEXT_STRING_SET 78 #define OP_OF_FOUND_AT 79 #define _OP_EQ 0 #define _OP_NEQ 1 #define _OP_LT 2 #define _OP_GT 3 #define _OP_LE 4 #define _OP_GE 5 #define _OP_ADD 6 #define _OP_SUB 7 #define _OP_MUL 8 #define _OP_DIV 9 #define _OP_MINUS 10 #define OP_INT_BEGIN 100 #define OP_INT_EQ (OP_INT_BEGIN + _OP_EQ) #define OP_INT_NEQ (OP_INT_BEGIN + _OP_NEQ) #define OP_INT_LT (OP_INT_BEGIN + _OP_LT) #define OP_INT_GT (OP_INT_BEGIN + _OP_GT) #define OP_INT_LE (OP_INT_BEGIN + _OP_LE) #define OP_INT_GE (OP_INT_BEGIN + _OP_GE) #define OP_INT_ADD (OP_INT_BEGIN + _OP_ADD) #define OP_INT_SUB (OP_INT_BEGIN + _OP_SUB) #define OP_INT_MUL (OP_INT_BEGIN + _OP_MUL) #define OP_INT_DIV (OP_INT_BEGIN + _OP_DIV) #define OP_INT_MINUS (OP_INT_BEGIN + _OP_MINUS) #define OP_INT_END OP_INT_MINUS #define OP_DBL_BEGIN 120 #define OP_DBL_EQ (OP_DBL_BEGIN + _OP_EQ) #define OP_DBL_NEQ (OP_DBL_BEGIN + _OP_NEQ) #define OP_DBL_LT (OP_DBL_BEGIN + _OP_LT) #define OP_DBL_GT (OP_DBL_BEGIN + _OP_GT) #define OP_DBL_LE (OP_DBL_BEGIN + _OP_LE) #define OP_DBL_GE (OP_DBL_BEGIN + _OP_GE) #define OP_DBL_ADD (OP_DBL_BEGIN + _OP_ADD) #define OP_DBL_SUB (OP_DBL_BEGIN + _OP_SUB) #define OP_DBL_MUL (OP_DBL_BEGIN + _OP_MUL) #define OP_DBL_DIV (OP_DBL_BEGIN + _OP_DIV) #define OP_DBL_MINUS (OP_DBL_BEGIN + _OP_MINUS) #define OP_DBL_END OP_DBL_MINUS #define OP_STR_BEGIN 140 #define OP_STR_EQ (OP_STR_BEGIN + _OP_EQ) #define OP_STR_NEQ (OP_STR_BEGIN + _OP_NEQ) #define OP_STR_LT (OP_STR_BEGIN + _OP_LT) #define OP_STR_GT (OP_STR_BEGIN + _OP_GT) #define OP_STR_LE (OP_STR_BEGIN + _OP_LE) #define OP_STR_GE (OP_STR_BEGIN + _OP_GE) #define OP_STR_END OP_STR_GE #define IS_INT_OP(x) ((x) >= OP_INT_BEGIN && (x) <= OP_INT_END) #define IS_DBL_OP(x) ((x) >= OP_DBL_BEGIN && (x) <= OP_DBL_END) #define IS_STR_OP(x) ((x) >= OP_STR_BEGIN && (x) <= OP_STR_END) #define OP_READ_INT 240 #define OP_INT8 (OP_READ_INT + 0) #define OP_INT16 (OP_READ_INT + 1) #define OP_INT32 (OP_READ_INT + 2) #define OP_UINT8 (OP_READ_INT + 3) #define OP_UINT16 (OP_READ_INT + 4) #define OP_UINT32 (OP_READ_INT + 5) #define OP_INT8BE (OP_READ_INT + 6) #define OP_INT16BE (OP_READ_INT + 7) #define OP_INT32BE (OP_READ_INT + 8) #define OP_UINT8BE (OP_READ_INT + 9) #define OP_UINT16BE (OP_READ_INT + 10) #define OP_UINT32BE (OP_READ_INT + 11) #define OPERATION(operator, op1, op2) \ (IS_UNDEFINED(op1) || IS_UNDEFINED(op2)) ? (YR_UNDEFINED) : (op1 operator op2) #define COMPARISON(operator, op1, op2) \ (IS_UNDEFINED(op1) || IS_UNDEFINED(op2)) ? (0) : (op1 operator op2) int yr_execute_code(YR_SCAN_CONTEXT* context); #endif yara-4.5.3/libyara/include/yara/exefiles.h000066400000000000000000000033241501365277300204510ustar00rootroot00000000000000/* Copyright (c) 2007. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_EXEFILES_H #define YR_EXEFILES_H uint64_t yr_get_entry_point_offset(const uint8_t* buffer, size_t buffer_length); uint64_t yr_get_entry_point_address( const uint8_t* buffer, size_t buffer_length, uint64_t base_address); #endif yara-4.5.3/libyara/include/yara/filemap.h000066400000000000000000000046231501365277300202650ustar00rootroot00000000000000/* Copyright (c) 2007-2015. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_FILEMAP_H #define YR_FILEMAP_H #include #if defined(_WIN32) || defined(__CYGWIN__) #include #define YR_FILE_DESCRIPTOR HANDLE #else #define YR_FILE_DESCRIPTOR int #endif #include #include #include typedef struct _YR_MAPPED_FILE { YR_FILE_DESCRIPTOR file; size_t size; const uint8_t* data; #if defined(_WIN32) || defined(__CYGWIN__) HANDLE mapping; #endif } YR_MAPPED_FILE; YR_API int yr_filemap_map(const char* file_path, YR_MAPPED_FILE* pmapped_file); YR_API int yr_filemap_map_fd( YR_FILE_DESCRIPTOR file, uint64_t offset, size_t size, YR_MAPPED_FILE* pmapped_file); YR_API int yr_filemap_map_ex( const char* file_path, uint64_t offset, size_t size, YR_MAPPED_FILE* pmapped_file); YR_API void yr_filemap_unmap(YR_MAPPED_FILE* pmapped_file); YR_API void yr_filemap_unmap_fd(YR_MAPPED_FILE* pmapped_file); #endif yara-4.5.3/libyara/include/yara/globals.h000066400000000000000000000113371501365277300202730ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_GLOBALS_H #define YR_GLOBALS_H #include #include // Pre-computed tables for quickly converting a character to lowercase or to // its alternative case (uppercase if it is a lowercase and vice versa). This // tables are initialized by yr_initialize. extern uint8_t yr_lowercase[256]; extern uint8_t yr_altercase[256]; // Thread-local storage (TLS) key used by the regexp and hex string parsers. // Each thread calling yr_parse_re_string/yr_parse_hex_string stores a pointer // to a jmp_buf struct used by setjmp/longjmp for recovering when a fatal error // occurs in the parser. extern YR_THREAD_STORAGE_KEY yr_yyfatal_trampoline_tls; // Thread-local storage (TLS) key used by YR_TRYCATCH. extern YR_THREAD_STORAGE_KEY yr_trycatch_trampoline_tls; #if !(_WIN32 || __CYGWIN__) extern struct sigaction old_sigsegv_exception_handler; extern struct sigaction old_sigbus_exception_handler; extern int exception_handler_usecount; extern pthread_mutex_t exception_handler_mutex; #endif // When YARA is built with YR_DEBUG_VERBOSITY defined as larger than 0 it can // print debug information to stdout. #if 0 == YR_DEBUG_VERBOSITY #define YR_DEBUG_INITIALIZE() #define YR_DEBUG_FPRINTF(VERBOSITY, FORMAT, ...) #else // for getpid() #include #include extern double yr_debug_get_elapsed_seconds(void); extern char* yr_debug_callback_message_as_string(int message); extern char* yr_debug_error_as_string(int error); // Default is 0 for production, which means be silent, else verbose. extern uint64_t yr_debug_verbosity; extern YR_TLS int yr_debug_indent; extern const char yr_debug_spaces[]; extern size_t yr_debug_spaces_len; #define YR_DEBUG_INITIALIZE() \ yr_debug_verbosity = getenv("YR_DEBUG_VERBOSITY") \ ? atoi(getenv("YR_DEBUG_VERBOSITY")) \ : YR_DEBUG_VERBOSITY #define YR_DEBUG_FPRINTF(VERBOSITY, STREAM, FORMAT, ...) \ if (yr_debug_verbosity >= VERBOSITY) \ { \ if (FORMAT[0] == '}') \ { \ yr_debug_indent--; \ } \ assert((2 * yr_debug_indent) >= 0); \ assert((2 * yr_debug_indent) < (yr_debug_spaces_len - 2)); \ fprintf( \ STREAM, \ "%f %06u %.*s", \ yr_debug_get_elapsed_seconds(), \ getpid(), \ (2 * yr_debug_indent), \ yr_debug_spaces); \ fprintf(STREAM, FORMAT, __VA_ARGS__); \ if (FORMAT[0] == '+') \ { \ yr_debug_indent++; \ } \ } #endif #endif yara-4.5.3/libyara/include/yara/hash.h000066400000000000000000000073651501365277300176010ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_HASH_H #define YR_HASH_H #include #include #include typedef struct _YR_HASH_TABLE_ENTRY { void* key; size_t key_length; char* ns; void* value; struct _YR_HASH_TABLE_ENTRY* next; } YR_HASH_TABLE_ENTRY; typedef struct _YR_HASH_TABLE { int size; YR_HASH_TABLE_ENTRY* buckets[1]; } YR_HASH_TABLE; typedef int (*YR_HASH_TABLE_FREE_VALUE_FUNC)(void* value); typedef int (*YR_HASH_TABLE_ITERATE_FUNC)( void* key, size_t key_length, void* value, void* data); uint32_t yr_hash(uint32_t seed, const void* buffer, size_t len); YR_API int yr_hash_table_create(int size, YR_HASH_TABLE** table); YR_API void yr_hash_table_clean( YR_HASH_TABLE* table, YR_HASH_TABLE_FREE_VALUE_FUNC free_value); YR_API void yr_hash_table_destroy( YR_HASH_TABLE* table, YR_HASH_TABLE_FREE_VALUE_FUNC free_value); YR_API int yr_hash_table_iterate( YR_HASH_TABLE* table, const char* ns, YR_HASH_TABLE_ITERATE_FUNC iterate_func, void* data); YR_API void* yr_hash_table_lookup( YR_HASH_TABLE* table, const char* key, const char* ns); YR_API void* yr_hash_table_remove( YR_HASH_TABLE* table, const char* key, const char* ns); YR_API int yr_hash_table_add( YR_HASH_TABLE* table, const char* key, const char* ns, void* value); YR_API int yr_hash_table_add_uint32( YR_HASH_TABLE* table, const char* key, const char* ns, uint32_t value); YR_API uint32_t yr_hash_table_lookup_uint32( YR_HASH_TABLE* table, const char* key, const char* ns); YR_API void* yr_hash_table_lookup_raw_key( YR_HASH_TABLE* table, const void* key, size_t key_length, const char* ns); YR_API void* yr_hash_table_remove_raw_key( YR_HASH_TABLE* table, const void* key, size_t key_length, const char* ns); YR_API int yr_hash_table_add_raw_key( YR_HASH_TABLE* table, const void* key, size_t key_length, const char* ns, void* value); YR_API int yr_hash_table_add_uint32_raw_key( YR_HASH_TABLE* table, const void* key, size_t key_length, const char* ns, uint32_t value); YR_API uint32_t yr_hash_table_lookup_uint32_raw_key( YR_HASH_TABLE* table, const void* key, size_t key_length, const char* ns); #endif yara-4.5.3/libyara/include/yara/hex_lexer.h000066400000000000000000000072651501365277300206400ustar00rootroot00000000000000/* Copyright (c) 2007. Victor M. Alvarez [plusvic@gmail.com]. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #undef yyparse #undef yylex #undef yyerror #undef yyfatal #undef yychar #undef yydebug #undef yynerrs #undef yyget_extra #undef yyget_lineno #undef YY_FATAL_ERROR #undef YY_DECL #undef LEX_ENV #define yyparse hex_yyparse #define yylex hex_yylex #define yyerror hex_yyerror #define yyfatal hex_yyfatal #define yychar hex_yychar #define yydebug hex_yydebug #define yynerrs hex_yynerrs #define yyget_extra hex_yyget_extra #define yyget_lineno hex_yyget_lineno // Define the ECHO macro as an empty macro in order to avoid the default // implementation from being used. The default implementation of ECHO // prints to the console any byte that is not matched by the lexer. It's // not safe to print random bytes to the console as it may cause the calling // program to terminate. See: https://github.com/VirusTotal/yara/issues/2007 #define ECHO #ifndef YY_TYPEDEF_YY_SCANNER_T #define YY_TYPEDEF_YY_SCANNER_T typedef void* yyscan_t; #endif #define YY_EXTRA_TYPE RE_AST* #define YY_USE_CONST typedef struct _HEX_LEX_ENVIRONMENT { int inside_or; int last_error; char last_error_message[256]; } HEX_LEX_ENVIRONMENT; // The default behavior when a fatal error occurs in the parser is calling // exit(YY_EXIT_FAILURE) for terminating the process. This is not acceptable // for a library, which should return gracefully to the calling program. For // this reason we redefine the YY_FATAL_ERROR macro so that it expands to our // own function instead of the one provided by default. #define YY_FATAL_ERROR(msg) hex_yyfatal(yyscanner, msg) #define LEX_ENV ((HEX_LEX_ENVIRONMENT*) lex_env) #include #define YY_DECL \ int hex_yylex( \ YYSTYPE* yylval_param, yyscan_t yyscanner, HEX_LEX_ENVIRONMENT* lex_env) YY_EXTRA_TYPE yyget_extra(yyscan_t yyscanner); int yylex( YYSTYPE* yylval_param, yyscan_t yyscanner, HEX_LEX_ENVIRONMENT* lex_env); int yyparse(void* yyscanner, HEX_LEX_ENVIRONMENT* lex_env); void yyerror( yyscan_t yyscanner, HEX_LEX_ENVIRONMENT* lex_env, const char* error_message); void yyfatal(yyscan_t yyscanner, const char* error_message); int yr_parse_hex_string( const char* hex_string, RE_AST** re_ast, RE_ERROR* error); yara-4.5.3/libyara/include/yara/integers.h000066400000000000000000000057651501365277300205000ustar00rootroot00000000000000/* Copyright (c) 2007-2015. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_INTEGERS_H #define YR_INTEGERS_H #if (defined(_MSC_VER) && (_MSC_VER < 1600)) || \ (defined(__BORLANDC__) && (__BORLANDC__ <= 0x0560)) #ifdef __cplusplus extern "C" { #endif // Microsoft Visual Studio C++ before Visual Studio 2010 or earlier versions // of the Borland C++ Builder do not support the (u)int#_t type definitions // but have __int# definitions instead typedef __int8 int8_t; typedef unsigned __int8 uint8_t; typedef __int16 int16_t; typedef unsigned __int16 uint16_t; typedef __int32 int32_t; typedef unsigned __int32 uint32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #ifdef __cplusplus } #endif #ifndef INT8_MIN #define INT8_MIN (-127i8 - 1) #endif #ifndef INT16_MIN #define INT16_MIN (-32767i16 - 1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647i32 - 1) #endif #ifndef INT64_MIN #define INT64_MIN (-9223372036854775807i64 - 1) #endif #ifndef INT8_MAX #define INT8_MAX 127i8 #endif #ifndef INT16_MAX #define INT16_MAX 32767i16 #endif #ifndef INT32_MAX #define INT32_MAX 2147483647i32 #endif #ifndef INT64_MAX #define INT64_MAX 9223372036854775807i64 #endif #ifndef UINT8_MAX #define UINT8_MAX 0xffui8 #endif #ifndef UINT16_MAX #define UINT16_MAX 0xffffui16 #endif #ifndef UINT32_MAX #define UINT32_MAX 0xffffffffui32 #endif #ifndef UINT64_MAX #define UINT64_MAX 0xffffffffffffffffui64 #endif #else // Other "compilers" and later versions of Microsoft Visual Studio C++ and // Borland C/C++ define the types in #include #endif #endif yara-4.5.3/libyara/include/yara/lexer.h000066400000000000000000000076311501365277300177710ustar00rootroot00000000000000/* Copyright (c) 2007. Victor M. Alvarez [plusvic@gmail.com]. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #undef yyparse #undef yylex #undef yyerror #undef yyfatal #undef yychar #undef yydebug #undef yynerrs #undef yyget_extra #undef yyget_lineno #undef YY_DECL #undef YY_FATAL_ERROR #undef YY_EXTRA_TYPE #define yyparse yara_yyparse #define yylex yara_yylex #define yyerror yara_yyerror #define yyfatal yara_yyfatal #define yywarning yara_yywarning #define yychar yara_yychar #define yydebug yara_yydebug #define yynerrs yara_yynerrs #define yyget_extra yara_yyget_extra #define yyget_lineno yara_yyget_lineno // Define the ECHO macro as an empty macro in order to avoid the default // implementation from being used. The default implementation of ECHO // prints to the console any byte that is not matched by the lexer. It's // not safe to print random bytes to the console as it may cause the calling // program to terminate. See: https://github.com/VirusTotal/yara/issues/2007 #define ECHO #ifndef YY_TYPEDEF_YY_SCANNER_T #define YY_TYPEDEF_YY_SCANNER_T typedef void* yyscan_t; #endif union YYSTYPE; #define YY_DECL \ int yylex( \ union YYSTYPE* yylval_param, yyscan_t yyscanner, YR_COMPILER* compiler) // The default behavior when a fatal error occurs in the parser is calling // exit(YY_EXIT_FAILURE) for terminating the process. This is not acceptable // for a library, which should return gracefully to the calling program. For // this reason we redefine the YY_FATAL_ERROR macro so that it expands to our // own function instead of the one provided by default. #define YY_FATAL_ERROR(msg) yara_yyfatal(yyscanner, msg) #define YY_EXTRA_TYPE YR_COMPILER* #define YY_USE_CONST int yyget_lineno(yyscan_t yyscanner); int yylex( union YYSTYPE* yylval_param, yyscan_t yyscanner, YR_COMPILER* compiler); int yyparse(void* yyscanner, YR_COMPILER* compiler); void yyerror( yyscan_t yyscanner, YR_COMPILER* compiler, const char* error_message); void yywarning(yyscan_t yyscanner, const char* message_fmt, ...) YR_PRINTF_LIKE(2, 3); void yyfatal(yyscan_t yyscanner, const char* error_message); YY_EXTRA_TYPE yyget_extra(yyscan_t yyscanner); int yr_lex_parse_rules_bytes( const void* rules_data, size_t rules_size, YR_COMPILER* compiler); int yr_lex_parse_rules_string(const char* rules_string, YR_COMPILER* compiler); int yr_lex_parse_rules_file(FILE* rules_file, YR_COMPILER* compiler); int yr_lex_parse_rules_fd(YR_FILE_DESCRIPTOR rules_fd, YR_COMPILER* compiler); yara-4.5.3/libyara/include/yara/libyara.h000066400000000000000000000075671501365277300203050ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_LIBYARA_H #define YR_LIBYARA_H #include #define YR_MAJOR_VERSION 4 #define YR_MINOR_VERSION 5 #define YR_MICRO_VERSION 2 #define version_str(s) _version_str(s) #define _version_str(s) #s // Version as a string #define YR_VERSION \ version_str(YR_MAJOR_VERSION) "." version_str( \ YR_MINOR_VERSION) "." version_str(YR_MICRO_VERSION) // Version as a single 4-byte hex number, e.g. 0x030401 == 3.4.1. #define YR_VERSION_HEX \ ((YR_MAJOR_VERSION << 16) | (YR_MINOR_VERSION << 8) | (YR_MICRO_VERSION << 0)) // Turn on paranoid mode by default if not defined otherwise. In paranoid // mode additional checks are performed in order to mitigate the effects of // malicious tampering with compiled rules. Such checks are not necessary // when you can ensure that the compiled rules are executed exactly as they // were generated by YARA, without any further modification. Check issue #891 // (https://github.com/VirusTotal/yara/issues/891) for more context. // // Paranoid mode does not guarantee that it's safe to load compiled rules from // third parties, it only prevents severe security issues. Maliciously crafted // compiled rules can still crash YARA. Loading third-party compiled rules is // *highly* discouraged. If you need to distribute YARA rules in compiled // form you should encapsulate them in some digitally-signed package that // ensure that they haven't been modified by someone else. #if !defined(YR_PARANOID_EXEC) #define YR_PARANOID_EXEC 1 #endif // Enumerated type listing configuration options typedef enum _YR_CONFIG_NAME { YR_CONFIG_STACK_SIZE, YR_CONFIG_MAX_STRINGS_PER_RULE, YR_CONFIG_MAX_MATCH_DATA, YR_CONFIG_MAX_PROCESS_MEMORY_CHUNK, YR_CONFIG_LAST // End-of-enum marker, not a configuration } YR_CONFIG_NAME; #define DEFAULT_STACK_SIZE 16384 #define DEFAULT_MAX_STRINGS_PER_RULE 10000 #define DEFAULT_MAX_MATCH_DATA 512 #define DEFAULT_MAX_PROCESS_MEMORY_CHUNK 1073741824 YR_API int yr_initialize(void); YR_API int yr_finalize(void); YR_API int yr_set_configuration(YR_CONFIG_NAME, void*); YR_API int yr_set_configuration_uint32(YR_CONFIG_NAME, uint32_t); YR_API int yr_set_configuration_uint64(YR_CONFIG_NAME, uint64_t); YR_API int yr_get_configuration(YR_CONFIG_NAME, void*); YR_API int yr_get_configuration_uint32(YR_CONFIG_NAME, uint32_t*); YR_API int yr_get_configuration_uint64(YR_CONFIG_NAME, uint64_t*); #endif yara-4.5.3/libyara/include/yara/limits.h000066400000000000000000000143721501365277300201530ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_LIMITS_H #define YR_LIMITS_H #if defined(_WIN32) || defined(__CYGWIN__) #include #endif #include "utils.h" // Maximum length of file paths. #ifndef YR_MAX_PATH #define YR_MAX_PATH 4096 #endif // Maximum number of threads that can use a YR_RULES structure simultaneously. // Increasing this number also increase memory usage as each YR_STRING structure // has an array with YR_MAX_THREADS entries for storing pointers to YR_MATCH // structures. #ifndef YR_MAX_THREADS #define YR_MAX_THREADS 32 #endif // Maximum number of buffers that an arena can have. #ifndef YR_MAX_ARENA_BUFFERS #define YR_MAX_ARENA_BUFFERS 16 #endif // Capacity of the buffer used for storing compiler error messages. Messages // will be truncated at this size. #ifndef YR_MAX_COMPILER_ERROR_EXTRA_INFO #define YR_MAX_COMPILER_ERROR_EXTRA_INFO 256 #endif // Maximum size for the substring (atoms) extracted from strings and regular // expressions and put into the Aho-Corasick automaton. The maximum allows size // for this constant is 255. #ifndef YR_MAX_ATOM_LENGTH #define YR_MAX_ATOM_LENGTH 4 #endif #ifndef YR_MAX_ATOM_QUALITY #define YR_MAX_ATOM_QUALITY 255 #endif #ifndef YR_MIN_ATOM_QUALITY #define YR_MIN_ATOM_QUALITY 0 #endif // If the minimum atom quality for a string or regexp is below this constant, // a warning like " is slowing down the scan" is shown. This is used // only with heuristic atom quality, when using an atom quality table the user // must specify the threshold when calling yr_compiler_set_atom_quality_table. #ifndef YR_ATOM_QUALITY_WARNING_THRESHOLD #define YR_ATOM_QUALITY_WARNING_THRESHOLD \ YR_MAX_ATOM_QUALITY - 22 * YR_MAX_ATOM_LENGTH + 38 #endif // If a rule generates more than this number of atoms a warning is shown. #ifndef YR_ATOMS_PER_RULE_WARNING_THRESHOLD #define YR_ATOMS_PER_RULE_WARNING_THRESHOLD 12000 #endif // Maximum number of nested "for" loops in rule. Rules ith nested loops // exceeding this number will be rejected by the compiler. #ifndef YR_MAX_LOOP_NESTING #define YR_MAX_LOOP_NESTING 4 #endif // Maximum number of local variables in a "for" loop. This includes the // variables defined explicitly defined by the user, not the internal variables // required for maintaining the loop's state. #ifndef YR_MAX_LOOP_VARS #define YR_MAX_LOOP_VARS 2 #endif // Maximum number of nested included files. #ifndef YR_MAX_INCLUDE_DEPTH #define YR_MAX_INCLUDE_DEPTH 16 #endif // Maximum number of matches allowed for a string. If more matches are found // the scan will have a CALLBACK_MSG_TOO_MANY_MATCHES. #ifndef YR_MAX_STRING_MATCHES #define YR_MAX_STRING_MATCHES 1000000 #endif // The number of matches before detecting slow scanning. If more matches are // found the scan will have a CALLBACK_MSG_TOO_SLOW_SCANNING. #ifndef YR_SLOW_STRING_MATCHES #define YR_SLOW_STRING_MATCHES 600000 #endif // If size of the input is bigger then 0.2 MB and 0-length atoms are used // the scan will have a CALLBACK_MSG_TOO_SLOW_SCANNING. #ifndef YR_FILE_SIZE_THRESHOLD #define YR_FILE_SIZE_THRESHOLD 200000 #endif // Maximum number of argument that a function in a YARA module can have. #ifndef YR_MAX_FUNCTION_ARGS #define YR_MAX_FUNCTION_ARGS 128 #endif // How many overloaded functions can share the same name in a YARA module. #ifndef YR_MAX_OVERLOADED_FUNCTIONS #define YR_MAX_OVERLOADED_FUNCTIONS 10 #endif // Regular expressions like /foo.{x,y}bar/ are split in two separate ones /foo/ // and /bar/ if x is larger than YR_STRING_CHAINING_THRESHOLD. This also applies // to hex strings like { 01 02 03 [x-y] 004 05 06 }. #ifndef YR_STRING_CHAINING_THRESHOLD #define YR_STRING_CHAINING_THRESHOLD 200 #endif // Size of the buffer used by the lexer for storing strings like include file // paths and regular expressions. #ifndef YR_LEX_BUF_SIZE #define YR_LEX_BUF_SIZE 8192 #endif // Each time an atom is found it means that we have a potential match for some // string, and that match must be verified. The time spent in verifying those // matches is measured in one out of YR_MATCH_VERIFICATION_PROFILING_RATE // matches. The time is not measured for all matches because measuring it is // expensive by itself and match verification is a frequent operation. #ifndef YR_MATCH_VERIFICATION_PROFILING_RATE #define YR_MATCH_VERIFICATION_PROFILING_RATE 1024 #endif // Maximum allowed split ID, also limiting the number of split instructions // allowed in a regular expression. This number can't be increased // over 255 without changing RE_SPLIT_ID_TYPE. #ifndef RE_MAX_SPLIT_ID #define RE_MAX_SPLIT_ID 128 #endif // Maximum stack size for regexp evaluation #ifndef RE_MAX_STACK #define RE_MAX_STACK 1024 #endif // Maximum input size scanned by yr_re_exec and yr_re_fast_exec #ifndef YR_RE_SCAN_LIMIT #define YR_RE_SCAN_LIMIT 1024 #endif // Maximum number of fibers #ifndef RE_MAX_FIBERS #define RE_MAX_FIBERS 1024 #endif #endif yara-4.5.3/libyara/include/yara/macho.h000066400000000000000000000375501501365277300177440ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _MACHO_H #define _MACHO_H #include // Mach-O file format magic constants #define MH_MAGIC 0xfeedface #define MH_CIGAM 0xcefaedfe #define MH_MAGIC_64 0xfeedfacf #define MH_CIGAM_64 0xcffaedfe // Mach-O universal binary magic constants #define FAT_MAGIC 0xcafebabe #define FAT_CIGAM 0xbebafeca #define FAT_MAGIC_64 0xcafebabf #define FAT_CIGAM_64 0xbfbafeca // Mach-O 64-bit masks #define CPU_ARCH_ABI64 0x01000000 // 64-bit ABI mask (for cputype) #define CPU_SUBTYPE_LIB64 0x80000000 // 64-bit library mask (for cpusubtype) // Mach-O CPU types #define CPU_TYPE_MC680X0 0x00000006 // Motorola 68000 #define CPU_TYPE_I386 0x00000007 // AMD/Intel x86 #define CPU_TYPE_X86 0x00000007 // AMD/Intel x86 #define CPU_TYPE_X86_64 0x01000007 // AMD/Intel x86-64 #define CPU_TYPE_MIPS 0x00000008 // MIPS #define CPU_TYPE_MC98000 0x0000000a // Motorola PowerPC #define CPU_TYPE_HPPA 0x0000000b // HP PA-RISC #define CPU_TYPE_ARM 0x0000000c // ARM #define CPU_TYPE_ARM64 0x0100000c // ARM 64-bit #define CPU_TYPE_MC88000 0x0000000d // Motorola 88000 #define CPU_TYPE_SPARC 0x0000000e // SPARC #define CPU_TYPE_I860 0x0000000f // Intel i860 #define CPU_TYPE_ALPHA 0x00000010 // DEC Alpha #define CPU_TYPE_POWERPC 0x00000012 // PowerPC #define CPU_TYPE_POWERPC64 0x01000012 // PowerPC 64-bit // Mach-O Intel CPU sub-types #define CPU_SUBTYPE_INTEL_MODEL_ALL 0x00 #define CPU_SUBTYPE_386 0x03 #define CPU_SUBTYPE_486 0x04 #define CPU_SUBTYPE_486SX 0x84 #define CPU_SUBTYPE_586 0x05 #define CPU_SUBTYPE_PENT 0x05 #define CPU_SUBTYPE_PENTPRO 0x16 #define CPU_SUBTYPE_PENTII_M3 0x36 #define CPU_SUBTYPE_PENTII_M5 0x56 #define CPU_SUBTYPE_CELERON 0x67 #define CPU_SUBTYPE_CELERON_MOBILE 0x77 #define CPU_SUBTYPE_PENTIUM_3 0x08 #define CPU_SUBTYPE_PENTIUM_3_M 0x18 #define CPU_SUBTYPE_PENTIUM_3_XEON 0x28 #define CPU_SUBTYPE_PENTIUM_M 0x09 #define CPU_SUBTYPE_PENTIUM_4 0x0a #define CPU_SUBTYPE_PENTIUM_4_M 0x1a #define CPU_SUBTYPE_ITANIUM 0x0b #define CPU_SUBTYPE_ITANIUM_2 0x1b #define CPU_SUBTYPE_XEON 0x0c #define CPU_SUBTYPE_XEON_MP 0x1c // Mach-O ARM CPU sub-types #define CPU_SUBTYPE_ARM_ALL 0x00 #define CPU_SUBTYPE_ARM_V4T 0x05 #define CPU_SUBTYPE_ARM_V6 0x06 #define CPU_SUBTYPE_ARM_V5 0x07 #define CPU_SUBTYPE_ARM_V5TEJ 0x07 #define CPU_SUBTYPE_ARM_XSCALE 0x08 #define CPU_SUBTYPE_ARM_V7 0x09 #define CPU_SUBTYPE_ARM_V7F 0x0a #define CPU_SUBTYPE_ARM_V7S 0x0b #define CPU_SUBTYPE_ARM_V7K 0x0c #define CPU_SUBTYPE_ARM_V6M 0x0e #define CPU_SUBTYPE_ARM_V7M 0x0f #define CPU_SUBTYPE_ARM_V7EM 0x10 // Mach-O ARM 64-bit CPU sub-types #define CPU_SUBTYPE_ARM64_ALL 0x00 // Mach-O SPARC CPU sub-types #define CPU_SUBTYPE_SPARC_ALL 0x00 // Mach-O PowerPC CPU sub-types #define CPU_SUBTYPE_POWERPC_ALL 0x00 #define CPU_SUBTYPE_MC980000_ALL 0x00 #define CPU_SUBTYPE_POWERPC_601 0x01 #define CPU_SUBTYPE_MC98601 0x01 #define CPU_SUBTYPE_POWERPC_602 0x02 #define CPU_SUBTYPE_POWERPC_603 0x03 #define CPU_SUBTYPE_POWERPC_603e 0x04 #define CPU_SUBTYPE_POWERPC_603ev 0x05 #define CPU_SUBTYPE_POWERPC_604 0x06 #define CPU_SUBTYPE_POWERPC_604e 0x07 #define CPU_SUBTYPE_POWERPC_620 0x08 #define CPU_SUBTYPE_POWERPC_750 0x09 #define CPU_SUBTYPE_POWERPC_7400 0x0a #define CPU_SUBTYPE_POWERPC_7450 0x0b #define CPU_SUBTYPE_POWERPC_970 0x64 // Mach-O file types #define MH_OBJECT 0x01 // Object file #define MH_EXECUTE 0x02 // Executable file #define MH_FVMLIB 0x03 // Fixed VM shared library #define MH_CORE 0x04 // Core dump file #define MH_PRELOAD 0x05 // Preloaded executable file #define MH_DYLIB 0x06 // Dynamic shared library #define MH_DYLINKER 0x07 // Dynamic linker shared library #define MH_BUNDLE 0x08 // Bundle file #define MH_DYLIB_STUB 0x09 // Dynamic shared library stub #define MH_DSYM 0x0a // Companion debug sections file #define MH_KEXT_BUNDLE 0x0b // Kernel extension // Mach-O file flags #define MH_NOUNDEFS 0x00000001 #define MH_INCRLINK 0x00000002 #define MH_DYLDLINK 0x00000004 #define MH_BINDATLOAD 0x00000008 #define MH_PREBOUND 0x00000010 #define MH_SPLIT_SEGS 0x00000020 #define MH_LAZY_INIT 0x00000040 #define MH_TWOLEVEL 0x00000080 #define MH_FORCE_FLAT 0x00000100 #define MH_NOMULTIDEFS 0x00000200 #define MH_NOFIXPREBINDING 0x00000400 #define MH_PREBINDABLE 0x00000800 #define MH_ALLMODSBOUND 0x00001000 #define MH_SUBSECTIONS_VIA_SYMBOLS 0x00002000 #define MH_CANONICAL 0x00004000 #define MH_WEAK_DEFINES 0x00008000 #define MH_BINDS_TO_WEAK 0x00010000 #define MH_ALLOW_STACK_EXECUTION 0x00020000 #define MH_ROOT_SAFE 0x00040000 #define MH_SETUID_SAFE 0x00080000 #define MH_NO_REEXPORTED_DYLIBS 0x00100000 #define MH_PIE 0x00200000 #define MH_DEAD_STRIPPABLE_DYLIB 0x00400000 #define MH_HAS_TLV_DESCRIPTORS 0x00800000 #define MH_NO_HEAP_EXECUTION 0x01000000 #define MH_APP_EXTENSION_SAFE 0x02000000 // Mach-O load commands #define LC_SEGMENT 0x00000001 #define LC_SYMTAB 0x00000002 #define LC_SYMSEG 0x00000003 #define LC_THREAD 0x00000004 #define LC_UNIXTHREAD 0x00000005 #define LC_LOADFVMLIB 0x00000006 #define LC_IDFVMLIB 0x00000007 #define LC_IDENT 0x00000008 #define LC_FVMFILE 0x00000009 #define LC_PREPAGE 0x0000000a #define LC_DYSYMTAB 0x0000000b #define LC_LOAD_DYLIB 0x0000000c #define LC_ID_DYLIB 0x0000000d #define LC_LOAD_DYLINKER 0x0000000e #define LC_ID_DYLINKER 0x0000000f #define LC_PREBOUND_DYLIB 0x00000010 #define LC_ROUTINES 0x00000011 #define LC_SUB_FRAMEWORK 0x00000012 #define LC_SUB_UMBRELLA 0x00000013 #define LC_SUB_CLIENT 0x00000014 #define LC_SUB_LIBRARY 0x00000015 #define LC_TWOLEVEL_HINTS 0x00000016 #define LC_PREBIND_CKSUM 0x00000017 #define LC_LOAD_WEAK_DYLIB 0x80000018 #define LC_SEGMENT_64 0x00000019 #define LC_ROUTINES_64 0x0000001A #define LC_UUID 0x0000001B #define LC_RPATH 0x8000001C #define LC_CODE_SIGNATURE 0x0000001D #define LC_SEGMENT_SPLIT_INFO 0x0000001E #define LC_REEXPORT_DYLIB 0x8000001F #define LC_LAZY_LOAD_DYLIB 0x00000020 #define LC_ENCRYPTION_INFO 0x00000021 #define LC_DYLD_INFO 0x00000022 #define LC_DYLD_INFO_ONLY 0x80000022 #define LC_LOAD_UPWARD_DYLIB 0x80000023 #define LC_VERSION_MIN_MACOSX 0x00000024 #define LC_VERSION_MIN_IPHONEOS 0x00000025 #define LC_FUNCTION_STARTS 0x00000026 #define LC_DYLD_ENVIRONMENT 0x00000027 #define LC_MAIN 0x80000028 #define LC_DATA_IN_CODE 0x00000029 #define LC_SOURCE_VERSION 0x0000002A #define LC_DYLIB_CODE_SIGN_DRS 0x0000002B #define LC_ENCRYPTION_INFO_64 0x0000002C #define LC_LINKER_OPTION 0x0000002D #define LC_LINKER_OPTIMIZATION_HINT 0x0000002E #define LC_VERSION_MIN_TVOS 0x0000002F #define LC_VERSION_MIN_WATCHOS 0x00000030 // Segment flags #define SG_HIGHVM 0x00000001 // Use high part of VM (stack) #define SG_FVMLIB 0x00000002 // Allocated by a fixed VM library #define SG_NORELOC 0x00000004 // No associated relocations #define SG_PROTECTED_VERSION_1 0x00000008 // Segment is encryption protected // Section flag masks #define SECTION_TYPE 0x000000ff // Section type mask #define SECTION_ATTRIBUTES 0xffffff00 // Section attributes mask // Section type (use SECTION_TYPE mask) #define S_REGULAR 0x00 #define S_ZEROFILL 0x01 #define S_CSTRING_LITERALS 0x02 #define S_4BYTE_LITERALS 0x03 #define S_8BYTE_LITERALS 0x04 #define S_LITERAL_POINTERS 0x05 #define S_NON_LAZY_SYMBOL_POINTERS 0x06 #define S_LAZY_SYMBOL_POINTERS 0x07 #define S_SYMBOL_STUBS 0x08 #define S_MOD_INIT_FUNC_POINTERS 0x09 #define S_MOD_TERM_FUNC_POINTERS 0x0a #define S_COALESCED 0x0b #define S_GB_ZEROFILL 0x0c #define S_INTERPOSING 0x0d #define S_16BYTE_LITERALS 0x0e #define S_DTRACE_DOF 0x0f #define S_LAZY_DYLIB_SYMBOL_POINTERS 0x10 #define S_THREAD_LOCAL_REGULAR 0x11 #define S_THREAD_LOCAL_ZEROFILL 0x12 #define S_THREAD_LOCAL_VARIABLES 0x13 #define S_THREAD_LOCAL_VARIABLE_POINTERS 0x14 #define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS 0x15 // Section attributes (use SECTION_ATTRIBUTES mask) #define S_ATTR_PURE_INSTRUCTIONS 0x80000000 // Only pure instructions #define S_ATTR_NO_TOC 0x40000000 // Contains coalesced symbols #define S_ATTR_STRIP_STATIC_SYMS 0x20000000 // Can strip static symbols #define S_ATTR_NO_DEAD_STRIP 0x10000000 // No dead stripping #define S_ATTR_LIVE_SUPPORT 0x08000000 // Live blocks support #define S_ATTR_SELF_MODIFYING_CODE 0x04000000 // Self modifying code #define S_ATTR_DEBUG 0x02000000 // Debug section #define S_ATTR_SOME_INSTRUCTIONS 0x00000400 // Some machine instructions #define S_ATTR_EXT_RELOC 0x00000200 // Has external relocations #define S_ATTR_LOC_RELOC 0x00000100 // Has local relocations #pragma pack(push, 1) typedef struct { uint32_t magic; uint32_t cputype; uint32_t cpusubtype; uint32_t filetype; uint32_t ncmds; uint32_t sizeofcmds; uint32_t flags; } yr_mach_header_32_t; typedef struct { uint32_t magic; uint32_t cputype; uint32_t cpusubtype; uint32_t filetype; uint32_t ncmds; uint32_t sizeofcmds; uint32_t flags; uint32_t reserved; } yr_mach_header_64_t; typedef struct { uint32_t cmd; uint32_t cmdsize; } yr_load_command_t; typedef struct { uint32_t cmd; uint32_t cmdsize; char segname[16]; uint32_t vmaddr; uint32_t vmsize; uint32_t fileoff; uint32_t filesize; uint32_t maxprot; uint32_t initprot; uint32_t nsects; uint32_t flags; } yr_segment_command_32_t; typedef struct { uint32_t cmd; uint32_t cmdsize; char segname[16]; uint64_t vmaddr; uint64_t vmsize; uint64_t fileoff; uint64_t filesize; uint32_t maxprot; uint32_t initprot; uint32_t nsects; uint32_t flags; } yr_segment_command_64_t; typedef struct { char sectname[16]; char segname[16]; uint32_t addr; uint32_t size; uint32_t offset; uint32_t align; uint32_t reloff; uint32_t nreloc; uint32_t flags; uint32_t reserved1; uint32_t reserved2; } yr_section_32_t; typedef struct { char sectname[16]; char segname[16]; uint64_t addr; uint64_t size; uint32_t offset; uint32_t align; uint32_t reloff; uint32_t nreloc; uint32_t flags; uint32_t reserved1; uint32_t reserved2; uint32_t reserved3; } yr_section_64_t; typedef struct { uint32_t cmd; uint32_t cmdsize; uint8_t uuid[16]; } yr_uuid_command_t; typedef struct { uint32_t cmd; uint32_t cmdsize; uint64_t entryoff; uint64_t stacksize; } yr_entry_point_command_t; typedef struct { uint32_t cmd; uint32_t cmdsize; uint32_t flavor; uint32_t count; // cpu_thread_state } yr_thread_command_t; typedef struct { uint32_t eax; uint32_t ebx; uint32_t ecx; uint32_t edx; uint32_t edi; uint32_t esi; uint32_t ebp; uint32_t esp; uint32_t ss; uint32_t eflags; uint32_t eip; uint32_t cs; uint32_t ds; uint32_t es; uint32_t fs; uint32_t gs; } yr_x86_thread_state_t; typedef struct { uint32_t r[13]; uint32_t sp; uint32_t lr; uint32_t pc; uint32_t cpsr; } yr_arm_thread_state_t; typedef struct { uint32_t srr0; uint32_t srr1; uint32_t r[32]; uint32_t cr; uint32_t xer; uint32_t lr; uint32_t ctr; uint32_t mq; uint32_t vrsavead; } yr_ppc_thread_state_t; typedef struct { uint32_t psr; uint32_t pc; uint32_t npc; uint32_t y; uint32_t g1; uint32_t g2; uint32_t g3; uint32_t g4; uint32_t g5; uint32_t g6; uint32_t g7; uint32_t o0; uint32_t o1; uint32_t o2; uint32_t o3; uint32_t o4; uint32_t o5; uint32_t o6; uint32_t o7; } yr_sparc_thread_state_t; typedef struct { uint32_t dreg[8]; uint32_t areg[8]; uint16_t pad; uint16_t sr; uint32_t pc; } yr_m68k_thread_state_t; typedef struct { uint32_t r1; uint32_t r2; uint32_t r3; uint32_t r4; uint32_t r5; uint32_t r6; uint32_t r7; uint32_t r8; uint32_t r9; uint32_t r10; uint32_t r11; uint32_t r12; uint32_t r13; uint32_t r14; uint32_t r15; uint32_t r16; uint32_t r17; uint32_t r18; uint32_t r19; uint32_t r20; uint32_t r21; uint32_t r22; uint32_t r23; uint32_t r24; uint32_t r25; uint32_t r26; uint32_t r27; uint32_t r28; uint32_t r29; uint32_t r30; uint32_t r31; uint32_t xip; uint32_t xip_in_bd; uint32_t nip; } yr_m88k_thread_state_t; typedef struct { uint64_t rax; uint64_t rbx; uint64_t rcx; uint64_t rdx; uint64_t rdi; uint64_t rsi; uint64_t rbp; uint64_t rsp; uint64_t r8; uint64_t r9; uint64_t r10; uint64_t r11; uint64_t r12; uint64_t r13; uint64_t r14; uint64_t r15; uint64_t rip; uint64_t rflags; uint64_t cs; uint64_t fs; uint64_t gs; } yr_x86_thread_state64_t; typedef struct { uint64_t r[29]; uint64_t fp; uint64_t lr; uint64_t sp; uint64_t pc; uint32_t cpsr; } yr_arm_thread_state64_t; typedef struct { uint64_t srr0; uint64_t srr1; uint64_t r[32]; uint32_t cr; uint64_t xer; uint64_t lr; uint64_t ctr; uint32_t vrsave; } yr_ppc_thread_state64_t; typedef struct { uint32_t magic; uint32_t nfat_arch; } yr_fat_header_t; typedef struct { uint32_t cputype; uint32_t cpusubtype; uint32_t offset; uint32_t size; uint32_t align; } yr_fat_arch_32_t; typedef struct { uint32_t cputype; uint32_t cpusubtype; uint64_t offset; uint64_t size; uint32_t align; uint32_t reserved; } yr_fat_arch_64_t; #pragma pack(pop) #endif yara-4.5.3/libyara/include/yara/mem.h000066400000000000000000000040331501365277300174210ustar00rootroot00000000000000/* Copyright (c) 2007. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_MEM_H #define YR_MEM_H #include #include #ifdef DMALLOC #define yr_malloc malloc #define yr_calloc calloc #define yr_realloc realloc #define yr_free free #define yr_strdup strdup #define yr_strndup strndup #include #else void* yr_calloc(size_t count, size_t size); void* yr_malloc(size_t size); void* yr_realloc(void* ptr, size_t size); char* yr_strdup(const char* str); char* yr_strndup(const char* str, size_t n); YR_API void yr_free(void* ptr); #endif int yr_heap_alloc(void); int yr_heap_free(void); #endif yara-4.5.3/libyara/include/yara/modules.h000066400000000000000000000344611501365277300203230ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_MODULES_H #define YR_MODULES_H #include #include #include #include #include #include #include #include #include #include #include #include // Concatenation that macro-expands its arguments. #define YR_CONCAT(arg1, arg2) _YR_CONCAT(arg1, arg2) // expands the arguments. #define _YR_CONCAT(arg1, arg2) arg1##arg2 // do the actual concatenation. #define module_declarations YR_CONCAT(MODULE_NAME, __declarations) #define module_load YR_CONCAT(MODULE_NAME, __load) #define module_unload YR_CONCAT(MODULE_NAME, __unload) #define module_initialize YR_CONCAT(MODULE_NAME, __initialize) #define module_finalize YR_CONCAT(MODULE_NAME, __finalize) #define begin_declarations \ int module_declarations(YR_OBJECT* module) \ { \ YR_OBJECT* stack[64]; \ int stack_top = 0; \ stack[stack_top] = module; #define end_declarations \ return ERROR_SUCCESS; \ } #define begin_struct(name) \ { \ YR_OBJECT* structure; \ FAIL_ON_ERROR(yr_object_create( \ OBJECT_TYPE_STRUCTURE, name, stack[stack_top], &structure)); \ assertf( \ stack_top < sizeof(stack) / sizeof(stack[0]) - 1, \ "too many nested structures"); \ stack[++stack_top] = structure; \ } #define begin_struct_array(name) \ { \ YR_OBJECT* structure; \ YR_OBJECT* array; \ FAIL_ON_ERROR( \ yr_object_create(OBJECT_TYPE_ARRAY, name, stack[stack_top], &array)); \ FAIL_ON_ERROR( \ yr_object_create(OBJECT_TYPE_STRUCTURE, name, array, &structure)); \ assertf( \ stack_top < sizeof(stack) / sizeof(stack[0]) - 1, \ "too many nested structures"); \ stack[++stack_top] = structure; \ } #define begin_struct_dictionary(name) \ { \ YR_OBJECT* structure; \ YR_OBJECT* array; \ FAIL_ON_ERROR(yr_object_create( \ OBJECT_TYPE_DICTIONARY, name, stack[stack_top], &array)); \ FAIL_ON_ERROR( \ yr_object_create(OBJECT_TYPE_STRUCTURE, name, array, &structure)); \ assertf( \ stack_top < sizeof(stack) / sizeof(stack[0]) - 1, \ "too many nested structures"); \ stack[++stack_top] = structure; \ } #define end_struct(name) \ { \ assert(stack[stack_top]->type == OBJECT_TYPE_STRUCTURE); \ assertf( \ strcmp(stack[stack_top]->identifier, name) == 0, \ "unbalanced begin_struct/end_struct"); \ stack_top--; \ } #define end_struct_array(name) \ end_struct \ (name) #define end_struct_dictionary(name) \ end_struct \ (name) #define declare_integer(name) \ { \ FAIL_ON_ERROR( \ yr_object_create(OBJECT_TYPE_INTEGER, name, stack[stack_top], NULL)); \ } #define declare_integer_array(name) \ { \ YR_OBJECT* array; \ FAIL_ON_ERROR( \ yr_object_create(OBJECT_TYPE_ARRAY, name, stack[stack_top], &array)); \ FAIL_ON_ERROR(yr_object_create(OBJECT_TYPE_INTEGER, name, array, NULL)); \ } #define declare_integer_dictionary(name) \ { \ YR_OBJECT* dict; \ FAIL_ON_ERROR(yr_object_create( \ OBJECT_TYPE_DICTIONARY, name, stack[stack_top], &dict)); \ FAIL_ON_ERROR(yr_object_create(OBJECT_TYPE_INTEGER, name, dict, NULL)); \ } #define declare_float(name) \ { \ FAIL_ON_ERROR( \ yr_object_create(OBJECT_TYPE_FLOAT, name, stack[stack_top], NULL)); \ } #define declare_float_array(name) \ { \ YR_OBJECT* array; \ FAIL_ON_ERROR( \ yr_object_create(OBJECT_TYPE_ARRAY, name, stack[stack_top], &array)); \ FAIL_ON_ERROR(yr_object_create(OBJECT_TYPE_FLOAT, name, array, NULL)); \ } #define declare_float_dictionary(name) \ { \ YR_OBJECT* dict; \ FAIL_ON_ERROR(yr_object_create( \ OBJECT_TYPE_DICTIONARY, name, stack[stack_top], &dict)); \ FAIL_ON_ERROR(yr_object_create(OBJECT_TYPE_FLOAT, name, dict, NULL)); \ } #define declare_string(name) \ { \ FAIL_ON_ERROR( \ yr_object_create(OBJECT_TYPE_STRING, name, stack[stack_top], NULL)); \ } #define declare_string_array(name) \ { \ YR_OBJECT* array; \ FAIL_ON_ERROR( \ yr_object_create(OBJECT_TYPE_ARRAY, name, stack[stack_top], &array)); \ FAIL_ON_ERROR(yr_object_create(OBJECT_TYPE_STRING, name, array, NULL)); \ } #define declare_string_dictionary(name) \ { \ YR_OBJECT* dict; \ FAIL_ON_ERROR(yr_object_create( \ OBJECT_TYPE_DICTIONARY, name, stack[stack_top], &dict)); \ FAIL_ON_ERROR(yr_object_create(OBJECT_TYPE_STRING, name, dict, NULL)); \ } #define declare_function(name, args_fmt, ret_fmt, func) \ { \ YR_OBJECT* function; \ FAIL_ON_ERROR(yr_object_function_create( \ name, args_fmt, ret_fmt, func, stack[stack_top], &function)); \ } #define define_function(func) \ int func( \ YR_VALUE* __args, \ YR_SCAN_CONTEXT* __context, \ YR_OBJECT_FUNCTION* __function_obj) #define sized_string_argument(n) (__args[n - 1].ss) #define string_argument(n) (sized_string_argument(n)->c_string) #define integer_argument(n) (__args[n - 1].i) #define float_argument(n) (__args[n - 1].d) #define regexp_argument(n) ((RE*) (__args[n - 1].re)) #define yr_module() yr_object_get_root((YR_OBJECT*) __function_obj) #define yr_parent() (__function_obj->parent) #define yr_scan_context() (__context) #define foreach_memory_block(iterator, block) \ for (block = iterator->first(iterator); block != NULL; \ block = iterator->next(iterator)) #define first_memory_block(context) \ (context)->iterator->first((context)->iterator) #define yr_is_undefined(object, ...) \ yr_object_has_undefined_value(object, __VA_ARGS__) #define yr_get_object(object, ...) yr_object_lookup(object, 0, __VA_ARGS__) #define yr_get_integer(object, ...) yr_object_get_integer(object, __VA_ARGS__) #define yr_get_float(object, ...) yr_object_get_float(object, __VA_ARGS__) #define yr_get_string(object, ...) yr_object_get_string(object, __VA_ARGS__) #define yr_set_integer(value, object, ...) \ yr_object_set_integer(value, object, __VA_ARGS__) #define yr_set_float(value, object, ...) \ yr_object_set_float(value, object, __VA_ARGS__) #define yr_set_sized_string(value, len, object, ...) \ yr_object_set_string(value, len, object, __VA_ARGS__) #define yr_set_string(value, object, ...) \ yr_set_sized_string( \ value, (value == NULL) ? 0 : strlen(value), object, __VA_ARGS__) #define return_integer(integer) \ { \ assertf( \ __function_obj->return_obj->type == OBJECT_TYPE_INTEGER, \ "return type differs from function declaration"); \ return yr_object_set_integer((integer), __function_obj->return_obj, NULL); \ } #define return_float(double_) \ { \ double d = (double) (double_); \ assertf( \ __function_obj->return_obj->type == OBJECT_TYPE_FLOAT, \ "return type differs from function declaration"); \ return yr_object_set_float( \ (d != (double) YR_UNDEFINED) ? d : NAN, \ __function_obj->return_obj, \ NULL); \ } #define return_string(string) \ { \ char* s = (char*) (string); \ assertf( \ __function_obj->return_obj->type == OBJECT_TYPE_STRING, \ "return type differs from function declaration"); \ return yr_object_set_string( \ (s != (char*) YR_UNDEFINED) ? s : NULL, \ (s != (char*) YR_UNDEFINED) ? strlen(s) : 0, \ __function_obj->return_obj, \ NULL); \ } typedef int (*YR_EXT_INITIALIZE_FUNC)(YR_MODULE* module); typedef int (*YR_EXT_FINALIZE_FUNC)(YR_MODULE* module); typedef int (*YR_EXT_DECLARATIONS_FUNC)(YR_OBJECT* module_object); typedef int (*YR_EXT_LOAD_FUNC)( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size); typedef int (*YR_EXT_UNLOAD_FUNC)(YR_OBJECT* module_object); struct YR_MODULE { char* name; YR_EXT_DECLARATIONS_FUNC declarations; YR_EXT_LOAD_FUNC load; YR_EXT_UNLOAD_FUNC unload; YR_EXT_INITIALIZE_FUNC initialize; YR_EXT_FINALIZE_FUNC finalize; }; struct YR_MODULE_IMPORT { const char* module_name; void* module_data; size_t module_data_size; }; int yr_modules_initialize(void); int yr_modules_finalize(void); int yr_modules_do_declarations( const char* module_name, YR_OBJECT* main_structure); int yr_modules_load(const char* module_name, YR_SCAN_CONTEXT* context); int yr_modules_unload_all(YR_SCAN_CONTEXT* context); YR_API YR_MODULE* yr_modules_get_table(void); #endif yara-4.5.3/libyara/include/yara/notebook.h000066400000000000000000000005441501365277300204660ustar00rootroot00000000000000// // Created by Victor Manuel Alvarez on 3/4/20. // #ifndef YR_NOTEBOOK_H #define YR_NOTEBOOK_H #include typedef struct YR_NOTEBOOK YR_NOTEBOOK; int yr_notebook_create(size_t page_size, YR_NOTEBOOK** pool); int yr_notebook_destroy(YR_NOTEBOOK* pool); void* yr_notebook_alloc(YR_NOTEBOOK* notebook, size_t size); #endif // YR_NOTEBOOK_H yara-4.5.3/libyara/include/yara/object.h000066400000000000000000000104551501365277300201160ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_OBJECT_H #define YR_OBJECT_H #ifdef _MSC_VER #include #ifndef yr_isnan #define yr_isnan _isnan #endif #else #ifndef yr_isnan #define yr_isnan isnan #endif #endif #ifndef INFINITY #define INFINITY (DBL_MAX + DBL_MAX) #endif #ifndef NAN #define NAN (INFINITY - INFINITY) #endif #include #include #include #define OBJECT_CREATE 1 #define OBJECT_TYPE_INTEGER 1 #define OBJECT_TYPE_STRING 2 #define OBJECT_TYPE_STRUCTURE 3 #define OBJECT_TYPE_ARRAY 4 #define OBJECT_TYPE_FUNCTION 5 #define OBJECT_TYPE_DICTIONARY 6 #define OBJECT_TYPE_FLOAT 7 int yr_object_create( int8_t type, const char* identifier, YR_OBJECT* parent, YR_OBJECT** object); void yr_object_set_canary(YR_OBJECT* object, int canary); int yr_object_function_create( const char* identifier, const char* arguments_fmt, const char* return_fmt, YR_MODULE_FUNC func, YR_OBJECT* parent, YR_OBJECT** function); int yr_object_from_external_variable( YR_EXTERNAL_VARIABLE* external, YR_OBJECT** object); void yr_object_destroy(YR_OBJECT* object); int yr_object_copy(YR_OBJECT* object, YR_OBJECT** object_copy); YR_OBJECT* yr_object_lookup_field(YR_OBJECT* object, const char* field_name); YR_OBJECT* yr_object_lookup( YR_OBJECT* root, int flags, const char* pattern, ...) YR_PRINTF_LIKE(3, 4); bool yr_object_has_undefined_value(YR_OBJECT* object, const char* field, ...) YR_PRINTF_LIKE(2, 3); double yr_object_get_float(YR_OBJECT* object, const char* field, ...) YR_PRINTF_LIKE(2, 3); int64_t yr_object_get_integer(YR_OBJECT* object, const char* field, ...) YR_PRINTF_LIKE(2, 3); SIZED_STRING* yr_object_get_string(YR_OBJECT* object, const char* field, ...) YR_PRINTF_LIKE(2, 3); int yr_object_set_integer( int64_t value, YR_OBJECT* object, const char* field, ...) YR_PRINTF_LIKE(3, 4); int yr_object_set_float(double value, YR_OBJECT* object, const char* field, ...) YR_PRINTF_LIKE(3, 4); int yr_object_set_string( const char* value, size_t len, YR_OBJECT* object, const char* field, ...) YR_PRINTF_LIKE(4, 5); YR_API int yr_object_array_length(YR_OBJECT* object); YR_API YR_OBJECT* yr_object_array_get_item(YR_OBJECT* object, int flags, int index); int yr_object_array_set_item(YR_OBJECT* object, YR_OBJECT* item, int index); YR_OBJECT* yr_object_dict_get_item( YR_OBJECT* object, int flags, const char* key); int yr_object_dict_set_item( YR_OBJECT* object, YR_OBJECT* item, const char* key); int yr_object_structure_set_member(YR_OBJECT* object, YR_OBJECT* member); YR_OBJECT* yr_object_get_root(YR_OBJECT* object); YR_API void yr_object_print_data( YR_OBJECT* object, int indent, int print_identifier); #endif yara-4.5.3/libyara/include/yara/parser.h000066400000000000000000000077531501365277300201530ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_PARSER_H #define YR_PARSER_H #include "lexer.h" int yr_parser_emit( yyscan_t yyscanner, uint8_t instruction, YR_ARENA_REF* instruction_ref); int yr_parser_emit_with_arg( yyscan_t yyscanner, uint8_t instruction, int64_t argument, YR_ARENA_REF* instruction_ref, YR_ARENA_REF* argument_ref); int yr_parser_emit_with_arg_int32( yyscan_t yyscanner, uint8_t instruction, int32_t argument, YR_ARENA_REF* instruction_ref, YR_ARENA_REF* argument_ref); int yr_parser_emit_with_arg_double( yyscan_t yyscanner, uint8_t instruction, double argument, YR_ARENA_REF* instruction_ref, YR_ARENA_REF* argument_ref); int yr_parser_emit_with_arg_reloc( yyscan_t yyscanner, uint8_t instruction, void* argument, YR_ARENA_REF* instruction_ref, YR_ARENA_REF* argument_ref); int yr_parser_emit_push_const(yyscan_t yyscanner, uint64_t argument); int yr_parser_check_types( YR_COMPILER* compiler, YR_OBJECT_FUNCTION* function, const char* actual_args_fmt); int yr_parser_lookup_string( yyscan_t yyscanner, const char* identifier, YR_STRING** string); int yr_parser_lookup_loop_variable( yyscan_t yyscanner, const char* identifier, YR_EXPRESSION*); int yr_parser_reduce_rule_declaration_phase_1( yyscan_t yyscanner, int32_t flags, const char* identifier, YR_ARENA_REF* rule_ref); int yr_parser_reduce_rule_declaration_phase_2( yyscan_t yyscanner, YR_ARENA_REF* rule_ref); int yr_parser_reduce_string_declaration( yyscan_t yyscanner, YR_MODIFIER modifier, const char* identifier, SIZED_STRING* str, YR_ARENA_REF* string_ref); int yr_parser_reduce_meta_declaration( yyscan_t yyscanner, int32_t type, const char* identifier, const char* string, int64_t integer, YR_ARENA_REF* meta_ref); int yr_parser_reduce_string_identifier( yyscan_t yyscanner, const char* identifier, uint8_t instruction, uint64_t at_offset); int yr_parser_emit_pushes_for_strings( yyscan_t yyscanner, const char* identifier, int* count); int yr_parser_emit_pushes_for_rules( yyscan_t yyscanner, const char* identifier, int *count); int yr_parser_reduce_external( yyscan_t yyscanner, const char* identifier, uint8_t instruction); int yr_parser_reduce_import(yyscan_t yyscanner, SIZED_STRING* module_name); int yr_parser_reduce_operation( yyscan_t yyscanner, const char* operation, YR_EXPRESSION left_operand, YR_EXPRESSION right_operand); #endif yara-4.5.3/libyara/include/yara/pe.h000066400000000000000000000653021501365277300172550ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_PE_H #define YR_PE_H #include #include #if defined(_WIN32) || defined(__CYGWIN__) #include // PKCS7_SIGNER_INFO is defined by wincrypt.h, but it conflicts with a type // defined in openssl/pkcs7.h which is used in pe.c. Let's undefine the macro. #undef PKCS7_SIGNER_INFO // These definitions are not present in older Windows headers. #ifndef IMAGE_FILE_MACHINE_ARMNT #define IMAGE_FILE_MACHINE_ARMNT 0x01c4 #endif #ifndef IMAGE_FILE_MACHINE_ARM64 #define IMAGE_FILE_MACHINE_ARM64 0xaa64 #endif #ifndef IMAGE_SUBSYSTEM_EFI_ROM_IMAGE #define IMAGE_SUBSYSTEM_EFI_ROM_IMAGE 13 #endif #ifndef IMAGE_DIRECTORY_ENTRY_COPYRIGHT #define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage) #endif #ifndef IMAGE_FILE_MACHINE_TARGET_HOST #define IMAGE_FILE_MACHINE_TARGET_HOST 0x0001 #endif #else #include #include typedef uint8_t BYTE; typedef uint16_t WORD; typedef uint16_t WCHAR; typedef int16_t SHORT; typedef uint32_t DWORD; typedef int32_t LONG; typedef uint32_t ULONG; typedef uint64_t ULONGLONG; #ifndef _MAC #define IMAGE_DOS_SIGNATURE 0x5A4D // MZ #define IMAGE_OS2_SIGNATURE 0x454E // NE #define IMAGE_OS2_SIGNATURE_LE 0x454C // LE #define IMAGE_VXD_SIGNATURE 0x454C // LE #define IMAGE_NT_SIGNATURE 0x00004550 // PE00 #else #define IMAGE_DOS_SIGNATURE 0x4D5A // MZ #define IMAGE_OS2_SIGNATURE 0x4E45 // NE #define IMAGE_OS2_SIGNATURE_LE 0x4C45 // LE #define IMAGE_NT_SIGNATURE 0x50450000 // PE00 #endif #pragma pack(push, 1) typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header WORD e_magic; // Magic number WORD e_cblp; // Bytes on last page of file WORD e_cp; // Pages in file WORD e_crlc; // Relocations WORD e_cparhdr; // Size of header in paragraphs WORD e_minalloc; // Minimum extra paragraphs needed WORD e_maxalloc; // Maximum extra paragraphs needed WORD e_ss; // Initial (relative) SS value WORD e_sp; // Initial SP value WORD e_csum; // Checksum WORD e_ip; // Initial IP value WORD e_cs; // Initial (relative) CS value WORD e_lfarlc; // File address of relocation table WORD e_ovno; // Overlay number WORD e_res[4]; // Reserved words WORD e_oemid; // OEM identifier (for e_oeminfo) WORD e_oeminfo; // OEM information; e_oemid specific WORD e_res2[10]; // Reserved words LONG e_lfanew; // File address of new exe header } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; typedef struct _IMAGE_FILE_HEADER { WORD Machine; WORD NumberOfSections; DWORD TimeDateStamp; DWORD PointerToSymbolTable; DWORD NumberOfSymbols; WORD SizeOfOptionalHeader; WORD Characteristics; } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; #define IMAGE_SIZEOF_FILE_HEADER 20 // Relocation info stripped from file. #define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // File is executable (i.e. no unresolved external references). #define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // Line numbers stripped from file. #define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Local symbols stripped from file. #define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Aggressively trim working set #define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 // App can handle >2gb addresses #define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 // Bytes of machine word are reversed. #define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // 32 bit word machine. #define IMAGE_FILE_32BIT_MACHINE 0x0100 // Debugging info stripped from file in .DBG file #define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // If Image is on removable media, copy and run from the swap file. #define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 // If Image is on Net, copy and run from the swap file. #define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 // System File. #define IMAGE_FILE_SYSTEM 0x1000 // File is a DLL.s #define IMAGE_FILE_DLL 0x2000 // File should only be run on a UP machine #define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 // Bytes of machine word are reversed. #define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 #define IMAGE_FILE_MACHINE_UNKNOWN 0x0000 #define IMAGE_FILE_MACHINE_AM33 0x01d3 #define IMAGE_FILE_MACHINE_AMD64 0x8664 #define IMAGE_FILE_MACHINE_ARM 0x01c0 #define IMAGE_FILE_MACHINE_ARMNT 0x01c4 #define IMAGE_FILE_MACHINE_ARM64 0xaa64 #define IMAGE_FILE_MACHINE_EBC 0x0ebc #define IMAGE_FILE_MACHINE_I386 0x014c #define IMAGE_FILE_MACHINE_IA64 0x0200 #define IMAGE_FILE_MACHINE_M32R 0x9041 #define IMAGE_FILE_MACHINE_MIPS16 0x0266 #define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 #define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 #define IMAGE_FILE_MACHINE_POWERPC 0x01f0 #define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1 #define IMAGE_FILE_MACHINE_R4000 0x0166 #define IMAGE_FILE_MACHINE_SH3 0x01a2 #define IMAGE_FILE_MACHINE_SH3DSP 0x01a3 #define IMAGE_FILE_MACHINE_SH4 0x01a6 #define IMAGE_FILE_MACHINE_SH5 0x01a8 #define IMAGE_FILE_MACHINE_THUMB 0x01c2 #define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 // Useful for indicating we want to interact with the host and not a WoW guest. #define IMAGE_FILE_MACHINE_TARGET_HOST 0x0001 // MIPS little-endian, 0x160 big-endian #define IMAGE_FILE_MACHINE_R3000 0x0162 // MIPS little-endian #define IMAGE_FILE_MACHINE_R10000 0x0168 // Alpha_AXP #define IMAGE_FILE_MACHINE_ALPHA 0x0184 // SH3E little-endian #define IMAGE_FILE_MACHINE_SH3E 0x01a4 // ALPHA64 #define IMAGE_FILE_MACHINE_ALPHA64 0x0284 #define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64 #define IMAGE_FILE_MACHINE_TRICORE 0x0520 // Infineon #define IMAGE_FILE_MACHINE_CEF 0x0CEF #define IMAGE_FILE_MACHINE_CEE 0xC0EE // Section characteristics #define IMAGE_SCN_TYPE_NO_PAD 0x00000008 #define IMAGE_SCN_CNT_CODE 0x00000020 #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 #define IMAGE_SCN_LNK_OTHER 0x00000100 #define IMAGE_SCN_LNK_INFO 0x00000200 #define IMAGE_SCN_LNK_REMOVE 0x00000800 #define IMAGE_SCN_LNK_COMDAT 0x00001000 #define IMAGE_SCN_NO_DEFER_SPEC_EXC 0x00004000 #define IMAGE_SCN_GPREL 0x00008000 #define IMAGE_SCN_MEM_FARDATA 0x00008000 #define IMAGE_SCN_MEM_PURGEABLE 0x00020000 #define IMAGE_SCN_MEM_16BIT 0x00020000 #define IMAGE_SCN_MEM_LOCKED 0x00040000 #define IMAGE_SCN_MEM_PRELOAD 0x00080000 #define IMAGE_SCN_ALIGN_1BYTES 0x00100000 #define IMAGE_SCN_ALIGN_2BYTES 0x00200000 #define IMAGE_SCN_ALIGN_4BYTES 0x00300000 #define IMAGE_SCN_ALIGN_8BYTES 0x00400000 #define IMAGE_SCN_ALIGN_16BYTES 0x00500000 #define IMAGE_SCN_ALIGN_32BYTES 0x00600000 #define IMAGE_SCN_ALIGN_64BYTES 0x00700000 #define IMAGE_SCN_ALIGN_128BYTES 0x00800000 #define IMAGE_SCN_ALIGN_256BYTES 0x00900000 #define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 #define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 #define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 #define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 #define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 #define IMAGE_SCN_ALIGN_MASK 0x00F00000 #define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 #define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 #define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 #define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 #define IMAGE_SCN_MEM_SHARED 0x10000000 #define IMAGE_SCN_MEM_EXECUTE 0x20000000 #define IMAGE_SCN_MEM_READ 0x40000000 #define IMAGE_SCN_MEM_WRITE 0x80000000 #define IMAGE_SCN_SCALE_INDEX 0x00000001 // // Directory format. // typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 #define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 #define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 #define IMAGE_DIRECTORY_ENTRY_SECURITY 4 #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 #define IMAGE_DIRECTORY_ENTRY_DEBUG 6 #define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 #define IMAGE_DIRECTORY_ENTRY_TLS 9 #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 #define IMAGE_DIRECTORY_ENTRY_IAT 12 #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // // Optional header format. // typedef struct _IMAGE_OPTIONAL_HEADER32 { WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; DWORD ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; WORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; typedef struct _IMAGE_OPTIONAL_HEADER64 { WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; ULONGLONG ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; WORD DllCharacteristics; ULONGLONG SizeOfStackReserve; ULONGLONG SizeOfStackCommit; ULONGLONG SizeOfHeapReserve; ULONGLONG SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; #define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b #define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b #define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 typedef struct _IMAGE_NT_HEADERS32 { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER32 OptionalHeader; } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; typedef struct _IMAGE_NT_HEADERS64 { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER64 OptionalHeader; } IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64; // IMAGE_FIRST_SECTION doesn't need 32/64 versions since the file header is // the same either way. #define IMAGE_FIRST_SECTION(ntheader) \ ((PIMAGE_SECTION_HEADER) ((BYTE*) ntheader + \ offsetof(IMAGE_NT_HEADERS32, OptionalHeader) + \ yr_le16toh( \ ((PIMAGE_NT_HEADERS32) (ntheader)) \ ->FileHeader.SizeOfOptionalHeader))) // Subsystem Values #define IMAGE_SUBSYSTEM_UNKNOWN 0 #define IMAGE_SUBSYSTEM_NATIVE 1 #define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 #define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 #define IMAGE_SUBSYSTEM_OS2_CUI 5 #define IMAGE_SUBSYSTEM_POSIX_CUI 7 #define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 #define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 #define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 #define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 #define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 #define IMAGE_SUBSYSTEM_EFI_ROM_IMAGE 13 #define IMAGE_SUBSYSTEM_XBOX 14 #define IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16 // DllCharacteristics values #define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 0x0020 #define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 #define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY 0x0080 #define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 #define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200 #define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 #define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 #define IMAGE_DLLCHARACTERISTICS_APPCONTAINER 0x1000 #define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 #define IMAGE_DLLCHARACTERISTICS_GUARD_CF 0x4000 #define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 // // Section header format. // #define IMAGE_SIZEOF_SHORT_NAME 8 typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; union { DWORD PhysicalAddress; DWORD VirtualSize; } Misc; DWORD VirtualAddress; DWORD SizeOfRawData; DWORD PointerToRawData; DWORD PointerToRelocations; DWORD PointerToLinenumbers; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; #define IMAGE_SIZEOF_SECTION_HEADER 40 typedef struct _IMAGE_EXPORT_DIRECTORY { DWORD Characteristics; DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; DWORD Name; DWORD Base; DWORD NumberOfFunctions; DWORD NumberOfNames; DWORD AddressOfFunctions; DWORD AddressOfNames; DWORD AddressOfNameOrdinals; } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; typedef struct _IMAGE_IMPORT_DESCRIPTOR { union { DWORD Characteristics; DWORD OriginalFirstThunk; }; DWORD TimeDateStamp; DWORD ForwarderChain; DWORD Name; DWORD FirstThunk; } IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR; typedef struct _IMAGE_IMPORT_BY_NAME { WORD Hint; BYTE Name[1]; } IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME; typedef struct _IMAGE_THUNK_DATA32 { union { DWORD ForwarderString; DWORD Function; DWORD Ordinal; DWORD AddressOfData; } u1; } IMAGE_THUNK_DATA32, *PIMAGE_THUNK_DATA32; #define IMAGE_ORDINAL_FLAG32 0x80000000 #define IMAGE_ORDINAL_FLAG64 0x8000000000000000L typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR { DWORD TimeDateStamp; WORD OffsetModuleName; WORD NumberOfModuleForwarderRefs; // Array of zero or more IMAGE_BOUND_FORWARDER_REF follows } IMAGE_BOUND_IMPORT_DESCRIPTOR, *PIMAGE_BOUND_IMPORT_DESCRIPTOR; typedef struct _IMAGE_BOUND_FORWARDER_REF { DWORD TimeDateStamp; WORD OffsetModuleName; WORD Reserved; } IMAGE_BOUND_FORWARDER_REF, *PIMAGE_BOUND_FORWARDER_REF; typedef struct _IMAGE_DELAYLOAD_DESCRIPTOR { union { DWORD AllAttributes; struct { DWORD RvaBased : 1; // Delay load version 2 DWORD ReservedAttributes : 31; } DUMMYSTRUCTNAME; } Attributes; // RVA to the name of the target library (NULL-terminate ASCII string) DWORD DllNameRVA; // RVA to the HMODULE caching location (PHMODULE) DWORD ModuleHandleRVA; // RVA to the start of the IAT (PIMAGE_THUNK_DATA) DWORD ImportAddressTableRVA; // RVA to the start of the name table (PIMAGE_THUNK_DATA::AddressOfData) DWORD ImportNameTableRVA; // RVA to an optional bound IAT DWORD BoundImportAddressTableRVA; // RVA to an optional unload info table DWORD UnloadInformationTableRVA; // 0 if not bound, otherwise, date/time of the target DLL DWORD TimeDateStamp; } IMAGE_DELAYLOAD_DESCRIPTOR, *PIMAGE_DELAYLOAD_DESCRIPTOR; typedef struct _IMAGE_THUNK_DATA64 { union { ULONGLONG ForwarderString; ULONGLONG Function; ULONGLONG Ordinal; ULONGLONG AddressOfData; } u1; } IMAGE_THUNK_DATA64, *PIMAGE_THUNK_DATA64; typedef struct _IMAGE_RESOURCE_DIR_STRING_U { WORD Length; WCHAR NameString[1]; } IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U; typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { DWORD Name; DWORD OffsetToData; } IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY; typedef struct _IMAGE_RESOURCE_DATA_ENTRY { DWORD OffsetToData; DWORD Size; DWORD CodePage; DWORD Reserved; } IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY; typedef struct _IMAGE_RESOURCE_DIRECTORY { DWORD Characteristics; DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; WORD NumberOfNamedEntries; WORD NumberOfIdEntries; } IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY; #define IMAGE_DEBUG_TYPE_FPO 3 #define IMAGE_DEBUG_TYPE_MISC 4 #define IMAGE_DEBUG_TYPE_EXCEPTION 5 #define IMAGE_DEBUG_TYPE_FIXUP 6 #define IMAGE_DEBUG_TYPE_OMAP_TO_SRC 7 #define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 8 #define IMAGE_DEBUG_TYPE_BORLAND 9 #define IMAGE_DEBUG_TYPE_RESERVED10 10 #define IMAGE_DEBUG_TYPE_CLSID 11 #define IMAGE_DEBUG_TYPE_VC_FEATURE 12 #define IMAGE_DEBUG_TYPE_POGO 13 #define IMAGE_DEBUG_TYPE_ILTCG 14 #define IMAGE_DEBUG_TYPE_MPX 15 #define IMAGE_DEBUG_TYPE_REPRO 16 typedef struct _IMAGE_DEBUG_DIRECTORY { DWORD Characteristics; DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; DWORD Type; DWORD SizeOfData; DWORD AddressOfRawData; DWORD PointerToRawData; } IMAGE_DEBUG_DIRECTORY, *PIMAGE_DEBUG_DIRECTORY; // // Symbol format. // typedef struct _IMAGE_SYMBOL { union { BYTE ShortName[8]; struct { DWORD Short; // if 0, use LongName DWORD Long; // offset into string table } Name; DWORD LongName[2]; // PBYTE [2] } N; DWORD Value; SHORT SectionNumber; WORD Type; BYTE StorageClass; BYTE NumberOfAuxSymbols; } IMAGE_SYMBOL, *PIMAGE_SYMBOL; #define IMAGE_SIZEOF_SYMBOL 18 typedef struct _IMAGE_SYMBOL_EX { union { BYTE ShortName[8]; struct { DWORD Short; // if 0, use LongName DWORD Long; // offset into string table } Name; DWORD LongName[2]; // PBYTE [2] } N; DWORD Value; LONG SectionNumber; WORD Type; BYTE StorageClass; BYTE NumberOfAuxSymbols; } IMAGE_SYMBOL_EX, *PIMAGE_SYMBOL_EX; // // Section values. // // Symbols have a section number of the section in which they are // defined. Otherwise, section numbers have the following meanings: // #define IMAGE_SYM_UNDEFINED (SHORT) 0 // Symbol is undefined or is common. #define IMAGE_SYM_ABSOLUTE (SHORT) - 1 // Symbol is an absolute value. #define IMAGE_SYM_DEBUG (SHORT) - 2 // Symbol is a special debug item. #define IMAGE_SYM_SECTION_MAX 0xFEFF // Values 0xFF00-0xFFFF are special #define IMAGE_SYM_SECTION_MAX_EX MAXLONG // // Type (fundamental) values. // #define IMAGE_SYM_TYPE_NULL 0x0000 // no type. #define IMAGE_SYM_TYPE_VOID 0x0001 // #define IMAGE_SYM_TYPE_CHAR 0x0002 // type character. #define IMAGE_SYM_TYPE_SHORT 0x0003 // type short integer. #define IMAGE_SYM_TYPE_INT 0x0004 // #define IMAGE_SYM_TYPE_LONG 0x0005 // #define IMAGE_SYM_TYPE_FLOAT 0x0006 // #define IMAGE_SYM_TYPE_DOUBLE 0x0007 // #define IMAGE_SYM_TYPE_STRUCT 0x0008 // #define IMAGE_SYM_TYPE_UNION 0x0009 // #define IMAGE_SYM_TYPE_ENUM 0x000A // enumeration. #define IMAGE_SYM_TYPE_MOE 0x000B // member of enumeration. #define IMAGE_SYM_TYPE_BYTE 0x000C // #define IMAGE_SYM_TYPE_WORD 0x000D // #define IMAGE_SYM_TYPE_UINT 0x000E // #define IMAGE_SYM_TYPE_DWORD 0x000F // #define IMAGE_SYM_TYPE_PCODE 0x8000 // // // Type (derived) values. // #define IMAGE_SYM_DTYPE_NULL 0 // no derived type. #define IMAGE_SYM_DTYPE_POINTER 1 // pointer. #define IMAGE_SYM_DTYPE_FUNCTION 2 // function. #define IMAGE_SYM_DTYPE_ARRAY 3 // array. // // Storage classes. // #define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE) - 1 #define IMAGE_SYM_CLASS_NULL 0x0000 #define IMAGE_SYM_CLASS_AUTOMATIC 0x0001 #define IMAGE_SYM_CLASS_EXTERNAL 0x0002 #define IMAGE_SYM_CLASS_STATIC 0x0003 #define IMAGE_SYM_CLASS_REGISTER 0x0004 #define IMAGE_SYM_CLASS_EXTERNAL_DEF 0x0005 #define IMAGE_SYM_CLASS_LABEL 0x0006 #define IMAGE_SYM_CLASS_UNDEFINED_LABEL 0x0007 #define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 0x0008 #define IMAGE_SYM_CLASS_ARGUMENT 0x0009 #define IMAGE_SYM_CLASS_STRUCT_TAG 0x000A #define IMAGE_SYM_CLASS_MEMBER_OF_UNION 0x000B #define IMAGE_SYM_CLASS_UNION_TAG 0x000C #define IMAGE_SYM_CLASS_TYPE_DEFINITION 0x000D #define IMAGE_SYM_CLASS_UNDEFINED_STATIC 0x000E #define IMAGE_SYM_CLASS_ENUM_TAG 0x000F #define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 0x0010 #define IMAGE_SYM_CLASS_REGISTER_PARAM 0x0011 #define IMAGE_SYM_CLASS_BIT_FIELD 0x0012 #define IMAGE_SYM_CLASS_FAR_EXTERNAL 0x0044 // #define IMAGE_SYM_CLASS_BLOCK 0x0064 #define IMAGE_SYM_CLASS_FUNCTION 0x0065 #define IMAGE_SYM_CLASS_END_OF_STRUCT 0x0066 #define IMAGE_SYM_CLASS_FILE 0x0067 // new #define IMAGE_SYM_CLASS_SECTION 0x0068 #define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069 #define IMAGE_SYM_CLASS_CLR_TOKEN 0x006B // type packing constants #define N_BTMASK 0x000F #define N_TMASK 0x0030 #define N_TMASK1 0x00C0 #define N_TMASK2 0x00F0 #define N_BTSHFT 4 #define N_TSHIFT 2 // MACROS // Basic Type of x #define BTYPE(x) ((x) & N_BTMASK) // Is x a pointer? #ifndef ISPTR #define ISPTR(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT)) #endif // Is x a function? #ifndef ISFCN #define ISFCN(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT)) #endif // Is x an array? #ifndef ISARY #define ISARY(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT)) #endif // Is x a structure, union, or enumeration TAG? #ifndef ISTAG #define ISTAG(x) \ ((x) == IMAGE_SYM_CLASS_STRUCT_TAG || (x) == IMAGE_SYM_CLASS_UNION_TAG || \ (x) == IMAGE_SYM_CLASS_ENUM_TAG) #endif #ifndef INCREF #define INCREF(x) \ ((((x) & ~N_BTMASK) << N_TSHIFT) | (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT) | \ ((x) & N_BTMASK)) #endif #ifndef DECREF #define DECREF(x) ((((x) >> N_TSHIFT) & ~N_BTMASK) | ((x) & N_BTMASK)) #endif #pragma pack(pop) #endif // _WIN32 || defined(__CYGWIN__) #define CVINFO_PDB70_CVSIGNATURE 0x53445352 // "RSDS" #define CVINFO_PDB20_CVSIGNATURE 0x3031424e // "NB10" #define CODEVIEW_SIGNATURE_MTOC 0x434f544d // "MTOC" #pragma pack(push, 1) typedef struct _CV_HEADER { DWORD dwSignature; DWORD dwOffset; } CV_HEADER, *PCV_HEADER; typedef struct _CV_INFO_PDB20 { CV_HEADER CvHeader; DWORD dwSignature; DWORD dwAge; BYTE PdbFileName[1]; } CV_INFO_PDB20, *PCV_INFO_PDB20; typedef struct _CV_INFO_PDB70 { DWORD CvSignature; DWORD Signature[4]; DWORD Age; BYTE PdbFileName[1]; } CV_INFO_PDB70, *PCV_INFO_PDB70; typedef struct _MTOC_ENTRY { DWORD Signature; BYTE uuid[16]; BYTE PdbFileName[1]; } MTOC_ENTRY, *PMTOC_ENTRY; typedef struct _VERSION_INFO { WORD Length; WORD ValueLength; WORD Type; char Key[0]; } VERSION_INFO, *PVERSION_INFO; #define MAX_PE_CERTS 16 #define WIN_CERT_REVISION_1_0 0x0100 #define WIN_CERT_REVISION_2_0 0x0200 #define WIN_CERT_TYPE_X509 0x0001 #define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002 #define WIN_CERT_TYPE_RESERVED_1 0x0003 #define WIN_CERT_TYPE_TS_STACK_SIGNED 0x0004 #define WIN_CERTIFICATE_HEADER_SIZE 8 typedef struct _WIN_CERTIFICATE { DWORD Length; WORD Revision; WORD CertificateType; BYTE Certificate[0]; } WIN_CERTIFICATE, *PWIN_CERTIFICATE; #define SPC_NESTED_SIGNATURE_OBJID "1.3.6.1.4.1.311.2.4.1" // // Rich signature. // http://www.ntcore.com/files/richsign.htm // #define RICH_VERSION_ID(id_version) (id_version >> 16) #define RICH_VERSION_VERSION(id_version) (id_version & 0xFFFF) #define IMAGE_DEBUG_TYPE_UNKNOWN 0 #define IMAGE_DEBUG_TYPE_COFF 1 #define IMAGE_DEBUG_TYPE_CODEVIEW 2 #define IMAGE_DEBUG_TYPE_FPO 3 #define IMAGE_DEBUG_TYPE_MISC 4 #define IMAGE_DEBUG_TYPE_EXCEPTION 5 #define IMAGE_DEBUG_TYPE_FIXUP 6 #define IMAGE_DEBUG_TYPE_OMAP_TO_SRC 7 #define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 8 #define IMAGE_DEBUG_TYPE_BORLAND 9 #define IMAGE_DEBUG_TYPE_RESERVED10 10 #define IMAGE_DEBUG_TYPE_CLSID 11 #define IMAGE_DEBUG_TYPE_VC_FEATURE 12 #define IMAGE_DEBUG_TYPE_POGO 13 #define IMAGE_DEBUG_TYPE_ILTCG 14 #define IMAGE_DEBUG_TYPE_MPX 15 #define IMAGE_DEBUG_TYPE_REPRO 16 typedef struct _RICH_VERSION_INFO { DWORD id_version; // tool id and version (use RICH_VERSION_ID and // RICH_VERSION_VERSION macros) DWORD times; // number of times this tool was used } RICH_VERSION_INFO, *PRICH_VERSION_INFO; typedef struct _RICH_SIGNATURE { DWORD dans; DWORD padding_1; DWORD padding_2; DWORD padding_3; RICH_VERSION_INFO versions[0]; } RICH_SIGNATURE, *PRICH_SIGNATURE; #define RICH_DANS 0x536e6144 // "DanS" #define RICH_RICH 0x68636952 // "Rich" #define PE_PAGE_SIZE 0x1000 #define PE_SECTOR_SIZE 0x0200 #pragma pack(pop) #endif yara-4.5.3/libyara/include/yara/pe_utils.h000066400000000000000000000042141501365277300204700ustar00rootroot00000000000000#ifndef YR_PE_UTILS_H #define YR_PE_UTILS_H #include #define MAX_PE_SECTIONS 96 #define IS_64BITS_PE(pe) \ (yr_le16toh(pe->header64->OptionalHeader.Magic) == \ IMAGE_NT_OPTIONAL_HDR64_MAGIC) #define OptionalHeader(pe, field) \ (IS_64BITS_PE(pe) ? pe->header64->OptionalHeader.field \ : pe->header->OptionalHeader.field) // // Imports are stored in a linked list. Each node (IMPORTED_DLL) contains the // name of the DLL and a pointer to another linked list of // IMPORT_EXPORT_FUNCTION structures containing the details of imported // functions. // typedef struct _IMPORTED_DLL { char* name; struct _IMPORT_FUNCTION* functions; struct _IMPORTED_DLL* next; } IMPORTED_DLL, *PIMPORTED_DLL; // // This is used to track imported and exported functions. The "has_ordinal" // field is only used in the case of imports as those are optional. Every export // has an ordinal so we don't need the field there, but in the interest of // keeping duplicate code to a minimum we use this function for both imports and // exports. // typedef struct _IMPORT_FUNCTION { char* name; uint8_t has_ordinal; uint16_t ordinal; uint64_t rva; struct _IMPORT_FUNCTION* next; } IMPORT_FUNCTION, *PIMPORT_FUNCTION; typedef struct _PE { const uint8_t* data; size_t data_size; union { PIMAGE_NT_HEADERS32 header; PIMAGE_NT_HEADERS64 header64; }; YR_HASH_TABLE* hash_table; YR_OBJECT* object; IMPORTED_DLL* imported_dlls; IMPORTED_DLL* delay_imported_dlls; uint32_t resources; uint32_t version_infos; } PE; #define fits_in_pe(pe, pointer, size) \ ((size_t)(size) <= pe->data_size && (uint8_t*) (pointer) >= pe->data && \ (uint8_t*) (pointer) <= pe->data + pe->data_size - (size)) #define struct_fits_in_pe(pe, pointer, struct_type) \ fits_in_pe(pe, pointer, sizeof(struct_type)) PIMAGE_NT_HEADERS32 pe_get_header(const uint8_t* data, size_t data_size); PIMAGE_DATA_DIRECTORY pe_get_directory_entry(PE* pe, int entry); int64_t pe_rva_to_offset(PE* pe, uint64_t rva); char* ord_lookup(char* dll, uint16_t ord); #endif yara-4.5.3/libyara/include/yara/proc.h000066400000000000000000000042071501365277300176110ustar00rootroot00000000000000/* Copyright (c) 2007. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_PROC_H #define YR_PROC_H #include typedef struct _YR_PROC_ITERATOR_CTX { const uint8_t* buffer; size_t buffer_size; YR_MEMORY_BLOCK current_block; void* proc_info; } YR_PROC_ITERATOR_CTX; YR_API int yr_process_open_iterator( int pid, YR_MEMORY_BLOCK_ITERATOR* iterator); YR_API int yr_process_close_iterator(YR_MEMORY_BLOCK_ITERATOR* iterator); YR_API YR_MEMORY_BLOCK* yr_process_get_first_memory_block( YR_MEMORY_BLOCK_ITERATOR* iterator); YR_API YR_MEMORY_BLOCK* yr_process_get_next_memory_block( YR_MEMORY_BLOCK_ITERATOR* iterator); YR_API const uint8_t* yr_process_fetch_memory_block_data( YR_MEMORY_BLOCK* block); #endif yara-4.5.3/libyara/include/yara/re.h000066400000000000000000000132751501365277300172610ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_RE_H #define YR_RE_H #include #include #include #include #include #define RE_MAX_RANGE INT16_MAX #define RE_NODE_LITERAL 1 #define RE_NODE_MASKED_LITERAL 2 #define RE_NODE_ANY 3 #define RE_NODE_CONCAT 4 #define RE_NODE_ALT 5 #define RE_NODE_RANGE 6 #define RE_NODE_STAR 7 #define RE_NODE_PLUS 8 #define RE_NODE_CLASS 9 #define RE_NODE_WORD_CHAR 10 #define RE_NODE_NON_WORD_CHAR 11 #define RE_NODE_SPACE 12 #define RE_NODE_NON_SPACE 13 #define RE_NODE_DIGIT 14 #define RE_NODE_NON_DIGIT 15 #define RE_NODE_EMPTY 16 #define RE_NODE_ANCHOR_START 17 #define RE_NODE_ANCHOR_END 18 #define RE_NODE_WORD_BOUNDARY 19 #define RE_NODE_NON_WORD_BOUNDARY 20 #define RE_NODE_RANGE_ANY 21 #define RE_NODE_NOT_LITERAL 22 #define RE_NODE_MASKED_NOT_LITERAL 23 #define RE_OPCODE_ANY 0xA0 #define RE_OPCODE_LITERAL 0xA2 #define RE_OPCODE_MASKED_LITERAL 0xA4 #define RE_OPCODE_CLASS 0xA5 #define RE_OPCODE_WORD_CHAR 0xA7 #define RE_OPCODE_NON_WORD_CHAR 0xA8 #define RE_OPCODE_SPACE 0xA9 #define RE_OPCODE_NON_SPACE 0xAA #define RE_OPCODE_DIGIT 0xAB #define RE_OPCODE_NON_DIGIT 0xAC #define RE_OPCODE_MATCH 0xAD #define RE_OPCODE_NOT_LITERAL 0xAE #define RE_OPCODE_MASKED_NOT_LITERAL 0xAF #define RE_OPCODE_MATCH_AT_END 0xB0 #define RE_OPCODE_MATCH_AT_START 0xB1 #define RE_OPCODE_WORD_BOUNDARY 0xB2 #define RE_OPCODE_NON_WORD_BOUNDARY 0xB3 #define RE_OPCODE_REPEAT_ANY_GREEDY 0xB4 #define RE_OPCODE_REPEAT_ANY_UNGREEDY 0xB5 #define RE_OPCODE_SPLIT_A 0xC0 #define RE_OPCODE_SPLIT_B 0xC1 #define RE_OPCODE_JUMP 0xC2 #define RE_OPCODE_REPEAT_START_GREEDY 0xC3 #define RE_OPCODE_REPEAT_END_GREEDY 0xC4 #define RE_OPCODE_REPEAT_START_UNGREEDY 0xC5 #define RE_OPCODE_REPEAT_END_UNGREEDY 0xC6 #define RE_FLAGS_FAST_REGEXP 0x02 #define RE_FLAGS_BACKWARDS 0x04 #define RE_FLAGS_EXHAUSTIVE 0x08 #define RE_FLAGS_WIDE 0x10 #define RE_FLAGS_NO_CASE 0x20 #define RE_FLAGS_SCAN 0x40 #define RE_FLAGS_DOT_ALL 0x80 #define RE_FLAGS_GREEDY 0x400 #define RE_FLAGS_UNGREEDY 0x800 enum YR_RE_PARSER_FLAGS { RE_PARSER_FLAG_NONE = 0 << 0, RE_PARSER_FLAG_ENABLE_STRICT_ESCAPE_SEQUENCES = 1 << 0, }; typedef int RE_MATCH_CALLBACK_FUNC( const uint8_t* match, int match_length, int flags, void* args); int yr_re_ast_create(RE_AST** re_ast); void yr_re_ast_destroy(RE_AST* re_ast); void yr_re_ast_print(RE_AST* re_ast); SIZED_STRING* yr_re_ast_extract_literal(RE_AST* re_ast); int yr_re_ast_has_unbounded_quantifier_for_dot(RE_AST* re_ast); int yr_re_ast_split_at_chaining_point( RE_AST* re_ast, RE_AST** remainder_re_ast, int32_t* min_gap, int32_t* max_gap); int yr_re_ast_emit_code(RE_AST* re_ast, YR_ARENA* arena, int backwards_code); RE_NODE* yr_re_node_create(int type); void yr_re_node_destroy(RE_NODE* node); void yr_re_node_append_child(RE_NODE* node, RE_NODE* child); void yr_re_node_prepend_child(RE_NODE* node, RE_NODE* child); int yr_re_exec( YR_SCAN_CONTEXT* context, const uint8_t* code, const uint8_t* input_data, size_t input_forwards_size, size_t input_backwards_size, int flags, RE_MATCH_CALLBACK_FUNC callback, void* callback_args, int* matches); int yr_re_fast_exec( YR_SCAN_CONTEXT* context, const uint8_t* code, const uint8_t* input_data, size_t input_forwards_size, size_t input_backwards_size, int flags, RE_MATCH_CALLBACK_FUNC callback, void* callback_args, int* matches); int yr_re_parse(const char* re_string, RE_AST** re_ast, RE_ERROR* error, int flags); int yr_re_parse_hex(const char* hex_string, RE_AST** re_ast, RE_ERROR* error); int yr_re_compile( const char* re_string, int flags, int parser_flags, YR_ARENA* arena, YR_ARENA_REF* ref, RE_ERROR* error); int yr_re_match(YR_SCAN_CONTEXT* context, RE* re, const char* target); #endif yara-4.5.3/libyara/include/yara/re_lexer.h000066400000000000000000000076211501365277300204560ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #undef yyparse #undef yylex #undef yyerror #undef yywarning #undef yyfatal #undef yychar #undef yydebug #undef yynerrs #undef yyget_extra #undef yyget_lineno #undef YY_FATAL_ERROR #undef YY_DECL #undef LEX_ENV #define yyparse re_yyparse #define yylex re_yylex #define yyerror re_yyerror #define yywarning re_yywarning #define yyfatal re_yyfatal #define yychar re_yychar #define yydebug re_yydebug #define yynerrs re_yynerrs #define yyget_extra re_yyget_extra #define yyget_lineno re_yyget_lineno // Define the ECHO macro as an empty macro in order to avoid the default // implementation from being used. The default implementation of ECHO // prints to the console any byte that is not matched by the lexer. It's // not safe to print random bytes to the console as it may cause the calling // program to terminate. See: https://github.com/VirusTotal/yara/issues/2007 #define ECHO #ifndef YY_TYPEDEF_YY_SCANNER_T #define YY_TYPEDEF_YY_SCANNER_T typedef void* yyscan_t; #endif #define YY_EXTRA_TYPE RE_AST* #define YY_USE_CONST #define VALID_ESCAPE_SEQUENCE 1 #define UNKNOWN_ESCAPE_SEQUENCE 2 typedef struct _RE_LEX_ENVIRONMENT { RE_CLASS re_class; int last_error; char last_error_message[256]; bool strict_escape; } RE_LEX_ENVIRONMENT; #define LEX_ENV ((RE_LEX_ENVIRONMENT*) lex_env) // The default behavior when a fatal error occurs in the parser is calling // exit(YY_EXIT_FAILURE) for terminating the process. This is not acceptable // for a library, which should return gracefully to the calling program. For // this reason we redefine the YY_FATAL_ERROR macro so that it expands to our // own function instead of the one provided by default. #define YY_FATAL_ERROR(msg) re_yyfatal(yyscanner, msg) #include #define YY_DECL \ int re_yylex( \ YYSTYPE* yylval_param, yyscan_t yyscanner, RE_LEX_ENVIRONMENT* lex_env) YY_EXTRA_TYPE yyget_extra(yyscan_t yyscanner); int yylex( YYSTYPE* yylval_param, yyscan_t yyscanner, RE_LEX_ENVIRONMENT* lex_env); void yyerror( yyscan_t yyscanner, RE_LEX_ENVIRONMENT* lex_env, const char* error_message); void yywarning( yyscan_t yyscanner, RE_LEX_ENVIRONMENT* lex_env, const char* error_message); void yyfatal(yyscan_t yyscanner, const char* error_message); int yyparse(void* yyscanner, RE_LEX_ENVIRONMENT* lex_env); int yr_parse_re_string( const char* re_string, RE_AST** re_ast, RE_ERROR* error, int flags); yara-4.5.3/libyara/include/yara/rules.h000066400000000000000000000117471501365277300200070ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_RULES_H #define YR_RULES_H #include #include #include #include #define CALLBACK_MSG_RULE_MATCHING 1 #define CALLBACK_MSG_RULE_NOT_MATCHING 2 #define CALLBACK_MSG_SCAN_FINISHED 3 #define CALLBACK_MSG_IMPORT_MODULE 4 #define CALLBACK_MSG_MODULE_IMPORTED 5 #define CALLBACK_MSG_TOO_MANY_MATCHES 6 #define CALLBACK_MSG_CONSOLE_LOG 7 #define CALLBACK_MSG_TOO_SLOW_SCANNING 8 #define CALLBACK_CONTINUE 0 #define CALLBACK_ABORT 1 #define CALLBACK_ERROR 2 #define yr_rule_tags_foreach(rule, tag_name) \ for (tag_name = rule->tags; tag_name != NULL && *tag_name != '\0'; \ tag_name += strlen(tag_name) + 1) #define yr_rule_metas_foreach(rule, meta) \ for (meta = rule->metas; meta != NULL; \ meta = META_IS_LAST_IN_RULE(meta) ? NULL : meta + 1) #define yr_rule_strings_foreach(rule, string) \ for (string = rule->strings; string != NULL; \ string = STRING_IS_LAST_IN_RULE(string) ? NULL : string + 1) #define yr_string_matches_foreach(context, string, match) \ for (match = context->matches[string->idx].head; match != NULL; \ match = match->next) \ /* private matches are skipped */ \ if (match->is_private) \ { \ continue; \ } \ else /* user code block goes here */ #define yr_rules_foreach(rules, rule) \ for (rule = rules->rules_table; !RULE_IS_NULL(rule); rule++) YR_API int yr_rules_scan_mem_blocks( YR_RULES* rules, YR_MEMORY_BLOCK_ITERATOR* iterator, int flags, YR_CALLBACK_FUNC callback, void* user_data, int timeout); YR_API int yr_rules_scan_mem( YR_RULES* rules, const uint8_t* buffer, size_t buffer_size, int flags, YR_CALLBACK_FUNC callback, void* user_data, int timeout); YR_API int yr_rules_scan_file( YR_RULES* rules, const char* filename, int flags, YR_CALLBACK_FUNC callback, void* user_data, int timeout); YR_API int yr_rules_scan_fd( YR_RULES* rules, YR_FILE_DESCRIPTOR fd, int flags, YR_CALLBACK_FUNC callback, void* user_data, int timeout); YR_API int yr_rules_scan_proc( YR_RULES* rules, int pid, int flags, YR_CALLBACK_FUNC callback, void* user_data, int timeout); YR_API int yr_rules_save(YR_RULES* rules, const char* filename); YR_API int yr_rules_save_stream(YR_RULES* rules, YR_STREAM* stream); YR_API int yr_rules_load(const char* filename, YR_RULES** rules); YR_API int yr_rules_load_stream(YR_STREAM* stream, YR_RULES** rules); YR_API int yr_rules_destroy(YR_RULES* rules); YR_API int yr_rules_define_integer_variable( YR_RULES* rules, const char* identifier, int64_t value); YR_API int yr_rules_define_boolean_variable( YR_RULES* rules, const char* identifier, int value); YR_API int yr_rules_define_float_variable( YR_RULES* rules, const char* identifier, double value); YR_API int yr_rules_define_string_variable( YR_RULES* rules, const char* identifier, const char* value); YR_API int yr_rules_get_stats(YR_RULES* rules, YR_RULES_STATS* stats); YR_API void yr_rule_disable(YR_RULE* rule); YR_API void yr_rule_enable(YR_RULE* rule); int yr_rules_from_arena(YR_ARENA* arena, YR_RULES** rules); #endif yara-4.5.3/libyara/include/yara/scan.h000066400000000000000000000040071501365277300175700ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_SCAN_H #define YR_SCAN_H #include // // Flags used with yr_scanner_set_flags and yr_rules_scan_xxx functions. // #define SCAN_FLAGS_FAST_MODE 1 #define SCAN_FLAGS_PROCESS_MEMORY 2 #define SCAN_FLAGS_NO_TRYCATCH 4 #define SCAN_FLAGS_REPORT_RULES_MATCHING 8 #define SCAN_FLAGS_REPORT_RULES_NOT_MATCHING 16 int yr_scan_verify_match( YR_SCAN_CONTEXT* context, YR_AC_MATCH* ac_match, const uint8_t* data, size_t data_size, uint64_t data_base, size_t offset); #endif yara-4.5.3/libyara/include/yara/scanner.h000066400000000000000000000063521501365277300203020ustar00rootroot00000000000000/* Copyright (c) 2018. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_SCANNER_H #define YR_SCANNER_H #include #include #include typedef YR_SCAN_CONTEXT YR_SCANNER; YR_API int yr_scanner_create(YR_RULES* rules, YR_SCANNER** scanner); YR_API void yr_scanner_destroy(YR_SCANNER* scanner); YR_API void yr_scanner_set_callback( YR_SCANNER* scanner, YR_CALLBACK_FUNC callback, void* user_data); YR_API void yr_scanner_set_timeout(YR_SCANNER* scanner, int timeout); YR_API void yr_scanner_set_flags(YR_SCANNER* scanner, int flags); YR_API int yr_scanner_define_integer_variable( YR_SCANNER* scanner, const char* identifier, int64_t value); YR_API int yr_scanner_define_boolean_variable( YR_SCANNER* scanner, const char* identifier, int value); YR_API int yr_scanner_define_float_variable( YR_SCANNER* scanner, const char* identifier, double value); YR_API int yr_scanner_define_string_variable( YR_SCANNER* scanner, const char* identifier, const char* value); YR_API int yr_scanner_scan_mem_blocks( YR_SCANNER* scanner, YR_MEMORY_BLOCK_ITERATOR* iterator); YR_API int yr_scanner_scan_mem( YR_SCANNER* scanner, const uint8_t* buffer, size_t buffer_size); YR_API int yr_scanner_scan_file(YR_SCANNER* scanner, const char* filename); YR_API int yr_scanner_scan_fd(YR_SCANNER* scanner, YR_FILE_DESCRIPTOR fd); YR_API int yr_scanner_scan_proc(YR_SCANNER* scanner, int pid); YR_API YR_RULE* yr_scanner_last_error_rule(YR_SCANNER* scanner); YR_API YR_STRING* yr_scanner_last_error_string(YR_SCANNER* scanner); YR_API YR_RULE_PROFILING_INFO* yr_scanner_get_profiling_info( YR_SCANNER* scanner); YR_API void yr_scanner_reset_profiling_info(YR_SCANNER* scanner); YR_API int yr_scanner_print_profiling_info(YR_SCANNER* scanner); #endif yara-4.5.3/libyara/include/yara/simple_str.h000066400000000000000000000007511501365277300210270ustar00rootroot00000000000000#ifndef _SIMPLESTR_H #define _SIMPLESTR_H #include /* Simple dynamic string implementation for more readable/maintainable code Can be further optimized */ typedef struct _SIMPLE_STR { uint32_t len; uint32_t cap; char* str; } SIMPLE_STR, *PSIMPLE_STR; SIMPLE_STR* sstr_new(const char* s); SIMPLE_STR* sstr_newf(const char* fmt, ...); void sstr_free(SIMPLE_STR* ss); bool sstr_appendf(SIMPLE_STR* ss, const char* fmt, ...); char* sstr_move(SIMPLE_STR* ss); #endifyara-4.5.3/libyara/include/yara/sizedstr.h000066400000000000000000000055031501365277300205150ustar00rootroot00000000000000/* Copyright (c) 2007-2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _SIZEDSTR_H #define _SIZEDSTR_H #include #include // SIZED_STRING_FLAGS_NO_CASE indicates that the has been decorated with // the "nocase" modifier or with the /i modifier in the case of regular // expressions. #define SIZED_STRING_FLAGS_NO_CASE 1 // SIZED_STRING_FLAGS_DOT_ALL is used for strings that contain a regular // expression that had the /s modifier. #define SIZED_STRING_FLAGS_DOT_ALL 2 #pragma pack(push) #pragma pack(1) // // This struct is used to support strings containing null chars. The length of // the string is stored along the string data. However the string data is also // terminated with a null char. // typedef struct _SIZED_STRING { uint32_t length; uint32_t flags; char c_string[1]; } SIZED_STRING; #pragma pack(pop) int ss_compare(SIZED_STRING* s1, SIZED_STRING* s2); int ss_icompare(SIZED_STRING* s1, SIZED_STRING* s2); bool ss_contains(SIZED_STRING* s1, SIZED_STRING* s2); bool ss_icontains(SIZED_STRING* s1, SIZED_STRING* s2); bool ss_startswith(SIZED_STRING* s1, SIZED_STRING* s2); bool ss_istartswith(SIZED_STRING* s1, SIZED_STRING* s2); bool ss_endswith(SIZED_STRING* s1, SIZED_STRING* s2); bool ss_iendswith(SIZED_STRING* s1, SIZED_STRING* s2); SIZED_STRING* ss_dup(SIZED_STRING* s); SIZED_STRING* ss_new(const char* s); SIZED_STRING* ss_convert_to_wide(SIZED_STRING* s); #endif yara-4.5.3/libyara/include/yara/stack.h000066400000000000000000000043111501365277300177470ustar00rootroot00000000000000/* Copyright (c) 2018. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_STACK_H #define YR_STACK_H typedef struct YR_STACK YR_STACK; struct YR_STACK { // Pointer to a heap-allocated array containing the void* values put in // in the stack. This array starts with a fixed size and it's grown as // required when new items are pushed into the stack. void* items; // Current capacity (i.e: the number of items that fit into the array) int capacity; // Size of each individual item in the stack. int item_size; // Index of the stack's top in the items array. int top; }; int yr_stack_create(int initial_capacity, int item_size, YR_STACK** stack); void yr_stack_destroy(YR_STACK* stack); int yr_stack_push(YR_STACK* stack, void* item); int yr_stack_pop(YR_STACK* stack, void* item); #endif yara-4.5.3/libyara/include/yara/stopwatch.h000066400000000000000000000044601501365277300206630ustar00rootroot00000000000000/* Copyright (c) 2017. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_STOPWATCH_H #define YR_STOPWATCH_H #include #include #if defined(_WIN32) #include typedef struct _YR_STOPWATCH { LARGE_INTEGER frequency; LARGE_INTEGER start; } YR_STOPWATCH; #elif defined(__APPLE__) && defined(__MACH__) #include typedef struct _YR_STOPWATCH { mach_timebase_info_data_t timebase; uint64_t start; } YR_STOPWATCH; #else #include typedef struct _YR_STOPWATCH { union { struct timeval tv_start; struct timespec ts_start; }; } YR_STOPWATCH; #endif // yr_stopwatch_start starts measuring time. void yr_stopwatch_start(YR_STOPWATCH* stopwatch); // yr_stopwatch_elapsed_ns returns the number of nanoseconds elapsed // since the last call to yr_stopwatch_start. uint64_t yr_stopwatch_elapsed_ns(YR_STOPWATCH* stopwatch); #endif yara-4.5.3/libyara/include/yara/stream.h000066400000000000000000000040661501365277300201440ustar00rootroot00000000000000/* Copyright (c) 2015. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_STREAM_H #define YR_STREAM_H #include typedef size_t (*YR_STREAM_READ_FUNC)( void* ptr, size_t size, size_t count, void* user_data); typedef size_t (*YR_STREAM_WRITE_FUNC)( const void* ptr, size_t size, size_t count, void* user_data); typedef struct _YR_STREAM { void* user_data; YR_STREAM_READ_FUNC read; YR_STREAM_WRITE_FUNC write; } YR_STREAM; size_t yr_stream_read(void* ptr, size_t size, size_t count, YR_STREAM* stream); size_t yr_stream_write( const void* ptr, size_t size, size_t count, YR_STREAM* stream); #endif yara-4.5.3/libyara/include/yara/strutils.h000066400000000000000000000057271501365277300205470ustar00rootroot00000000000000/* Copyright (c) 2007-2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_STRUTILS_H #define YR_STRUTILS_H #include #include #include #include #include #if defined(_WIN32) #if !defined(PRIu64) #define PRIu64 "I64u" #endif #if !defined(PRIu32) #define PRIu32 "I32u" #endif #if !defined(PRIx64) #define PRIx64 "I64x" #endif #if !defined(PRId64) #define PRId64 "I64d" #endif #if !defined(PRIi32) #define PRIi32 "I32i" #endif #if !defined(PRIi64) #define PRIi64 "I64i" #endif #if !defined(PRIo64) #define PRIo64 "I64o" #endif #else #include #endif // Cygwin already has these functions. #if defined(_WIN32) && !defined(__CYGWIN__) #if defined(_MSC_VER) && _MSC_VER < 1900 #if !defined(snprintf) #define snprintf _snprintf #endif #endif #define strcasecmp _stricmp #define strncasecmp _strnicmp #endif uint64_t xtoi(const char* hexstr); #if !HAVE_STRLCPY && !defined(strlcpy) size_t strlcpy(char* dst, const char* src, size_t size); #endif #if !HAVE_STRLCAT && !defined(strlcat) size_t strlcat(char* dst, const char* src, size_t size); #endif #if !HAVE_MEMMEM && !defined(memmem) void* memmem( const void* haystack, size_t haystack_size, const void* needle, size_t needle_size); #endif int strnlen_w(const char* w_str); int strcmp_w(const char* w_str, const char* str); size_t strlcpy_w(char* dst, const char* w_src, size_t n); #endif int yr_isalnum(const uint8_t* s); void yr_vasprintf(char** strp, const char* fmt, va_list ap); void yr_asprintf(char** strp, const char* fmt, ...); yara-4.5.3/libyara/include/yara/threading.h000066400000000000000000000044061501365277300206140ustar00rootroot00000000000000/* Copyright (c) 2016. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_MUTEX_H #define YR_MUTEX_H #if defined(_WIN32) || defined(__CYGWIN__) #include typedef DWORD YR_THREAD_ID; typedef DWORD YR_THREAD_STORAGE_KEY; typedef HANDLE YR_MUTEX; #define YR_TLS __declspec(thread) #else #include typedef pthread_t YR_THREAD_ID; typedef pthread_key_t YR_THREAD_STORAGE_KEY; typedef pthread_mutex_t YR_MUTEX; #define YR_TLS __thread #endif YR_THREAD_ID yr_current_thread_id(void); int yr_mutex_create(YR_MUTEX*); int yr_mutex_destroy(YR_MUTEX*); int yr_mutex_lock(YR_MUTEX*); int yr_mutex_unlock(YR_MUTEX*); int yr_thread_storage_create(YR_THREAD_STORAGE_KEY*); int yr_thread_storage_destroy(YR_THREAD_STORAGE_KEY*); int yr_thread_storage_set_value(YR_THREAD_STORAGE_KEY*, void*); void* yr_thread_storage_get_value(YR_THREAD_STORAGE_KEY*); #endif yara-4.5.3/libyara/include/yara/types.h000066400000000000000000000735631501365277300200250ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_TYPES_H #define YR_TYPES_H #include #include #include #include #include #include #include #include #include "notebook.h" #define DECLARE_REFERENCE(type, name) \ union \ { \ type name; \ YR_ARENA_REF name##_; \ } YR_ALIGN(8) // Flags for YR_RULE #define RULE_FLAGS_PRIVATE 0x01 #define RULE_FLAGS_GLOBAL 0x02 #define RULE_FLAGS_NULL 0x04 #define RULE_FLAGS_DISABLED 0x08 #define RULE_IS_PRIVATE(x) (((x)->flags) & RULE_FLAGS_PRIVATE) #define RULE_IS_GLOBAL(x) (((x)->flags) & RULE_FLAGS_GLOBAL) #define RULE_IS_NULL(x) (((x)->flags) & RULE_FLAGS_NULL) #define RULE_IS_DISABLED(x) (((x)->flags) & RULE_FLAGS_DISABLED) // Flags for YR_STRING #define STRING_FLAGS_REFERENCED 0x01 #define STRING_FLAGS_HEXADECIMAL 0x02 #define STRING_FLAGS_NO_CASE 0x04 #define STRING_FLAGS_ASCII 0x08 #define STRING_FLAGS_WIDE 0x10 #define STRING_FLAGS_REGEXP 0x20 #define STRING_FLAGS_FAST_REGEXP 0x40 #define STRING_FLAGS_FULL_WORD 0x80 #define STRING_FLAGS_ANONYMOUS 0x100 #define STRING_FLAGS_SINGLE_MATCH 0x200 #define STRING_FLAGS_LITERAL 0x400 #define STRING_FLAGS_FITS_IN_ATOM 0x800 #define STRING_FLAGS_LAST_IN_RULE 0x1000 #define STRING_FLAGS_CHAIN_PART 0x2000 #define STRING_FLAGS_CHAIN_TAIL 0x4000 #define STRING_FLAGS_FIXED_OFFSET 0x8000 #define STRING_FLAGS_GREEDY_REGEXP 0x10000 #define STRING_FLAGS_DOT_ALL 0x20000 #define STRING_FLAGS_DISABLED 0x40000 #define STRING_FLAGS_XOR 0x80000 #define STRING_FLAGS_PRIVATE 0x100000 #define STRING_FLAGS_BASE64 0x200000 #define STRING_FLAGS_BASE64_WIDE 0x400000 #define STRING_IS_HEX(x) (((x)->flags) & STRING_FLAGS_HEXADECIMAL) #define STRING_IS_NO_CASE(x) (((x)->flags) & STRING_FLAGS_NO_CASE) #define STRING_IS_DOT_ALL(x) (((x)->flags) & STRING_FLAGS_DOT_ALL) #define STRING_IS_ASCII(x) (((x)->flags) & STRING_FLAGS_ASCII) #define STRING_IS_WIDE(x) (((x)->flags) & STRING_FLAGS_WIDE) #define STRING_IS_REGEXP(x) (((x)->flags) & STRING_FLAGS_REGEXP) #define STRING_IS_GREEDY_REGEXP(x) (((x)->flags) & STRING_FLAGS_GREEDY_REGEXP) #define STRING_IS_FULL_WORD(x) (((x)->flags) & STRING_FLAGS_FULL_WORD) #define STRING_IS_ANONYMOUS(x) (((x)->flags) & STRING_FLAGS_ANONYMOUS) #define STRING_IS_REFERENCED(x) (((x)->flags) & STRING_FLAGS_REFERENCED) #define STRING_IS_SINGLE_MATCH(x) (((x)->flags) & STRING_FLAGS_SINGLE_MATCH) #define STRING_IS_FIXED_OFFSET(x) (((x)->flags) & STRING_FLAGS_FIXED_OFFSET) #define STRING_IS_LITERAL(x) (((x)->flags) & STRING_FLAGS_LITERAL) #define STRING_IS_FAST_REGEXP(x) (((x)->flags) & STRING_FLAGS_FAST_REGEXP) #define STRING_IS_CHAIN_PART(x) (((x)->flags) & STRING_FLAGS_CHAIN_PART) #define STRING_IS_CHAIN_TAIL(x) (((x)->flags) & STRING_FLAGS_CHAIN_TAIL) #define STRING_IS_LAST_IN_RULE(x) (((x)->flags) & STRING_FLAGS_LAST_IN_RULE) #define STRING_FITS_IN_ATOM(x) (((x)->flags) & STRING_FLAGS_FITS_IN_ATOM) #define STRING_IS_DISABLED(x) (((x)->flags) & STRING_FLAGS_DISABLED) #define STRING_IS_XOR(x) (((x)->flags) & STRING_FLAGS_XOR) #define STRING_IS_BASE64(x) (((x)->flags) & STRING_FLAGS_BASE64) #define STRING_IS_BASE64_WIDE(x) (((x)->flags) & STRING_FLAGS_BASE64_WIDE) #define STRING_IS_PRIVATE(x) (((x)->flags) & STRING_FLAGS_PRIVATE) #define META_TYPE_INTEGER 1 #define META_TYPE_STRING 2 #define META_TYPE_BOOLEAN 3 #define META_FLAGS_LAST_IN_RULE 1 #define META_IS_LAST_IN_RULE(x) (((x)->flags) & META_FLAGS_LAST_IN_RULE) #define EXTERNAL_VARIABLE_TYPE_NULL 0 #define EXTERNAL_VARIABLE_TYPE_FLOAT 1 #define EXTERNAL_VARIABLE_TYPE_INTEGER 2 #define EXTERNAL_VARIABLE_TYPE_BOOLEAN 3 #define EXTERNAL_VARIABLE_TYPE_STRING 4 #define EXTERNAL_VARIABLE_TYPE_MALLOC_STRING 5 #define EXTERNAL_VARIABLE_IS_NULL(x) \ ((x) != NULL ? (x)->type == EXTERNAL_VARIABLE_TYPE_NULL : true) typedef struct RE RE; typedef struct RE_AST RE_AST; typedef struct RE_NODE RE_NODE; typedef struct RE_CLASS RE_CLASS; typedef struct RE_ERROR RE_ERROR; typedef struct RE_FIBER RE_FIBER; typedef struct RE_FIBER_LIST RE_FIBER_LIST; typedef struct RE_FIBER_POOL RE_FIBER_POOL; typedef struct RE_FAST_EXEC_POSITION RE_FAST_EXEC_POSITION; typedef struct RE_FAST_EXEC_POSITION_LIST RE_FAST_EXEC_POSITION_LIST; typedef struct RE_FAST_EXEC_POSITION_POOL RE_FAST_EXEC_POSITION_POOL; typedef struct YR_AC_STATE YR_AC_STATE; typedef struct YR_AC_AUTOMATON YR_AC_AUTOMATON; typedef struct YR_AC_TABLES YR_AC_TABLES; typedef struct YR_AC_MATCH_LIST_ENTRY YR_AC_MATCH_LIST_ENTRY; typedef struct YR_AC_MATCH YR_AC_MATCH; typedef struct YR_NAMESPACE YR_NAMESPACE; typedef struct YR_META YR_META; typedef struct YR_MATCHES YR_MATCHES; typedef struct YR_STRING YR_STRING; typedef struct YR_RULE YR_RULE; typedef struct YR_RULES YR_RULES; typedef struct YR_SUMMARY YR_SUMMARY; typedef struct YR_RULES_STATS YR_RULES_STATS; typedef struct YR_PROFILING_INFO YR_PROFILING_INFO; typedef struct YR_RULE_PROFILING_INFO YR_RULE_PROFILING_INFO; typedef struct YR_EXTERNAL_VARIABLE YR_EXTERNAL_VARIABLE; typedef struct YR_MATCH YR_MATCH; typedef struct YR_SCAN_CONTEXT YR_SCAN_CONTEXT; typedef union YR_VALUE YR_VALUE; typedef struct YR_VALUE_STACK YR_VALUE_STACK; typedef struct YR_OBJECT YR_OBJECT; typedef struct YR_OBJECT_STRUCTURE YR_OBJECT_STRUCTURE; typedef struct YR_OBJECT_ARRAY YR_OBJECT_ARRAY; typedef struct YR_OBJECT_DICTIONARY YR_OBJECT_DICTIONARY; typedef struct YR_OBJECT_FUNCTION YR_OBJECT_FUNCTION; typedef struct YR_STRUCTURE_MEMBER YR_STRUCTURE_MEMBER; typedef struct YR_ARRAY_ITEMS YR_ARRAY_ITEMS; typedef struct YR_DICTIONARY_ITEMS YR_DICTIONARY_ITEMS; typedef struct YR_MODULE YR_MODULE; typedef struct YR_MODULE_IMPORT YR_MODULE_IMPORT; typedef struct YR_MEMORY_BLOCK YR_MEMORY_BLOCK; typedef struct YR_MEMORY_BLOCK_ITERATOR YR_MEMORY_BLOCK_ITERATOR; typedef struct YR_MODIFIER YR_MODIFIER; typedef struct YR_ITERATOR YR_ITERATOR; typedef uint32_t YR_AC_TRANSITION; #pragma pack(push) #pragma pack(8) struct YR_NAMESPACE { // Pointer to namespace's name. DECLARE_REFERENCE(const char*, name); // Index of this namespace in the array of YR_NAMESPACE structures stored // in YR_NAMESPACES_TABLE. // // YR_ALIGN(8) forces the idx field to be treated as a 8-bytes field // and therefore the struct's size is 16 bytes. This is necessary only for // 32-bits versions of YARA compiled with Visual Studio. See: #1358. YR_ALIGN(8) uint32_t idx; }; struct YR_META { DECLARE_REFERENCE(const char*, identifier); DECLARE_REFERENCE(const char*, string); int64_t integer; int32_t type; int32_t flags; }; struct YR_STRING { // Flags, see STRING_FLAGS_XXX macros defined above. uint32_t flags; // Index of this string in the array of YR_STRING structures stored in // YR_STRINGS_TABLE. uint32_t idx; // If the string can only match at a specific offset (for example if the // condition is "$a at 0" the string $a can only match at offset 0), the // fixed_offset field contains the offset, it have the YR_UNDEFINED value for // strings that can match anywhere. int64_t fixed_offset; // Index of the rule containing this string in the array of YR_RULE // structures stored in YR_RULES_TABLE. uint32_t rule_idx; // String's length. int32_t length; // Pointer to the string itself, the length is indicated by the "length" // field. DECLARE_REFERENCE(uint8_t*, string); // Strings are splitted in two or more parts when they contain a "gap" that // is larger than YR_STRING_CHAINING_THRESHOLD. This happens in strings like // { 01 02 03 04 [X-Y] 05 06 07 08 } if Y >= X + YR_STRING_CHAINING_THRESHOLD // and also in { 01 02 03 04 [-] 05 06 07 08 }. In both cases the strings are // split in { 01 02 03 04 } and { 05 06 07 08 }, and the two smaller strings // are searched for independently. If some string S is splitted in S1 and S2, // S2 is chained to S1. In the example above { 05 06 07 08 } is chained to // { 01 02 03 04 }. The same applies when the string is splitted in more than // two parts, if S is split in S1, S2, and S3. S3 is chained to S2 and S2 is // chained to S1 (it can represented as: S1 <- S2 <- S3). DECLARE_REFERENCE(YR_STRING*, chained_to); // When this string is chained to some other string, chain_gap_min and // chain_gap_max contain the minimum and maximum distance between the two // strings. For example in { 01 02 03 04 [X-Y] 05 06 07 08 }, the string // { 05 06 07 08 } is chained to { 01 02 03 04 } and chain_gap_min is X // and chain_gap_max is Y. These fields are ignored for strings that are not // part of a string chain. int32_t chain_gap_min; int32_t chain_gap_max; // Identifier of this string. DECLARE_REFERENCE(const char*, identifier); }; struct YR_RULE { int32_t flags; // Number of atoms generated for this rule. int32_t num_atoms; // Number of strings that must match for this rule to have some possibility // to match. uint32_t required_strings; // Just for padding. uint32_t unused; DECLARE_REFERENCE(const char*, identifier); DECLARE_REFERENCE(const char*, tags); DECLARE_REFERENCE(YR_META*, metas); DECLARE_REFERENCE(YR_STRING*, strings); DECLARE_REFERENCE(YR_NAMESPACE*, ns); }; struct YR_SUMMARY { uint32_t num_rules; uint32_t num_strings; uint32_t num_namespaces; }; struct YR_EXTERNAL_VARIABLE { int32_t type; YR_ALIGN(8) union { int64_t i; double f; char* s; } value; DECLARE_REFERENCE(const char*, identifier); }; struct YR_AC_MATCH { DECLARE_REFERENCE(YR_STRING*, string); DECLARE_REFERENCE(const uint8_t*, forward_code); DECLARE_REFERENCE(const uint8_t*, backward_code); DECLARE_REFERENCE(YR_AC_MATCH*, next); // When the Aho-Corasick automaton reaches some state that has associated // matches, the current position in the input buffer is a few bytes past // the point where the match actually occurs, for example, when looking for // string "bar" in "foobarbaz", when the automaton reaches the state // associated to the ending "r" in "bar, which is the one that has a match, // the current position in the input is 6 (the "b" after the "r"), but the // match is at position 3. The backtrack field indicates how many bytes the // scanner has to go back to find the point where the match actually start. // // YR_ALIGN(8) forces the backtrack field to be treated as a 8-bytes field // and therefore the struct's size is 40 bytes. This is necessary only for // 32-bits versions of YARA compiled with Visual Studio. See: #1358. YR_ALIGN(8) uint16_t backtrack; }; #pragma pack(pop) // // Structs defined below are never stored in the compiled rules file // struct RE_NODE { int type; union { int value; int count; int start; }; union { int mask; int end; }; int greedy; RE_CLASS* re_class; RE_NODE* children_head; RE_NODE* children_tail; RE_NODE* prev_sibling; RE_NODE* next_sibling; YR_ARENA_REF forward_code_ref; YR_ARENA_REF backward_code_ref; }; struct RE_CLASS { uint8_t negated; uint8_t bitmap[32]; }; struct RE_AST { uint32_t flags; RE_NODE* root_node; }; // Disable warning due to zero length array in Microsoft's compiler #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4200) #endif // The RE structure is embedded in the YARA's VM instruction flow, which // means that its alignment is not guaranteed. For this reason the it must // be a "packed" structure, in order to prevent alignment issues in platforms // with strict alignment constraints. #pragma pack(push) #pragma pack(1) struct RE { uint32_t flags; uint8_t code[0]; }; #pragma pack(pop) #ifdef _MSC_VER #pragma warning(pop) #endif struct RE_ERROR { char message[384]; }; struct RE_FIBER { const uint8_t* ip; // instruction pointer int32_t sp; // stack pointer int32_t rc; // repeat counter RE_FIBER* prev; RE_FIBER* next; uint16_t stack[RE_MAX_STACK]; }; struct RE_FIBER_LIST { RE_FIBER* head; RE_FIBER* tail; }; struct RE_FIBER_POOL { int fiber_count; RE_FIBER_LIST fibers; }; struct RE_FAST_EXEC_POSITION { int round; const uint8_t* input; RE_FAST_EXEC_POSITION* prev; RE_FAST_EXEC_POSITION* next; }; struct RE_FAST_EXEC_POSITION_POOL { RE_FAST_EXEC_POSITION* head; }; struct YR_MODIFIER { int32_t flags; uint8_t xor_min; uint8_t xor_max; SIZED_STRING* alphabet; }; struct YR_MATCHES { YR_MATCH* head; YR_MATCH* tail; int32_t count; }; struct YR_MATCH { int64_t base; // Base address for the match int64_t offset; // Offset relative to base for the match int32_t match_length; // Match length int32_t data_length; // Pointer to a buffer containing a portion of the matched data. The size of // the buffer is data_length. data_length is always <= length and is limited // to YR_CONFIG_MAX_MATCH_DATA bytes. const uint8_t* data; YR_MATCH* prev; YR_MATCH* next; // If the match belongs to a chained string chain_length contains the // length of the chain. This field is used only in unconfirmed matches. int32_t chain_length; // True if this is match for a private string. bool is_private; // Set to the xor key if this is an xor string. uint8_t xor_key; }; struct YR_AC_STATE { YR_AC_STATE* failure; YR_AC_STATE* first_child; YR_AC_STATE* siblings; // Reference to the YR_AC_MATCH structure that heads the list of matches // for this state. YR_ARENA_REF matches_ref; uint8_t depth; uint8_t input; uint32_t t_table_slot; }; struct YR_AC_MATCH_LIST_ENTRY { uint16_t backtrack; uint32_t string_idx; YR_ARENA_REF ref; YR_ARENA_REF forward_code_ref; YR_ARENA_REF backward_code_ref; YR_AC_MATCH_LIST_ENTRY* next; }; struct YR_AC_AUTOMATON { // Arena used by this automaton to store the transition and match tables. YR_ARENA* arena; // Both m_table and t_table have the same number of elements, which is // stored in tables_size. uint32_t tables_size; // The first slot in the transition table (t_table) that may be be unused. // Used for speeding up the construction of the transition table. uint32_t t_table_unused_candidate; // Bitmask where each bit indicates if the corresponding slot in the // transition table is already in use. YR_BITMASK* bitmask; // Pointer to the root Aho-Corasick state. YR_AC_STATE* root; }; struct YR_RULES { YR_ARENA* arena; // Array of pointers with an entry for each rule. The rule_idx field in the // YR_STRING structure is an index within this array. union { YR_RULE* rules_table; // The previous name for rules_table was rules_list_head, because this // was previously a linked list. The old name is maintained but marked as // deprecated, which will raise a warning if used. // TODO(vmalvarez): Remove this field when a reasonable a few versions // after 4.1 has been released. YR_DEPRECATED(YR_RULE* rules_list_head); }; // Array of pointers with an entry for each of the defined strings. The idx // field in the YR_STRING structure is an index within this array. union { YR_STRING* strings_table; // The previous name for strings_table was strings_list_head, because this // was previously a linked list. The old name is maintained but marked as // deprecated, which will raise a warning if used. // TODO(vmalvarez): Remove this field when a reasonable a few versions // after 4.1 has been released. YR_DEPRECATED(YR_STRING* strings_list_head); }; // Array of pointers with an entry for each external variable. union { YR_EXTERNAL_VARIABLE* ext_vars_table; // The previous name for ext_vars_table was externals_list_head, because // this was previously a linked list. The old name is maintained but marked // as deprecated, which will raise a warning if used. // TODO(vmalvarez): Remove this field when a reasonable a few versions // after 4.1 has been released. YR_DEPRECATED(YR_EXTERNAL_VARIABLE* externals_list_head); }; // Pointer to the Aho-Corasick transition table. YR_AC_TRANSITION* ac_transition_table; // A pointer to the arena where YR_AC_MATCH structures are allocated. YR_AC_MATCH* ac_match_pool; // Table that translates from Aho-Corasick states (which are identified by // numbers 0, 1, 2.. and so on) to the index in ac_match_pool where the // YR_AC_MATCH structures for the corresponding state start. // If the entry corresponding to state N in ac_match_table is zero, it // means that there's no match associated to the state. If it's non-zero, // its value is the 1-based index within ac_match_pool where the first // match resides. uint32_t* ac_match_table; // Pointer to the first instruction that is executed whan evaluating the // conditions for all rules. The code is executed by yr_execute_code and // the instructions are defined by the OP_X macros in exec.h. const uint8_t* code_start; // A bitmap with one bit per rule, bit N is set when the condition for rule // might evaluate to true even without any string matches. YR_BITMASK* no_required_strings; // Total number of rules. uint32_t num_rules; // Total number of strings. uint32_t num_strings; // Total number of namespaces. uint32_t num_namespaces; }; struct YR_RULES_STATS { // Total number of rules uint32_t num_rules; // Total number of strings across all rules. uint32_t num_strings; // Total number of Aho-Corasick matches. Each node in the Aho-Corasick // automaton has a list of YR_AC_MATCH_LIST_ENTRY structures (match list) // pointing to strings that are potential matches. This field holds the total // number of those structures across all nodes in the automaton. uint32_t ac_matches; // Length of the match list for the root node in the Aho-Corasick automaton. uint32_t ac_root_match_list_length; // Average number of matches per match list. float ac_average_match_list_length; // Top 10 longest match lists. uint32_t top_ac_match_list_lengths[100]; // Percentiles of match lists' lengths. If the i-th value in the array is N // then i percent of the match lists have N or less items. uint32_t ac_match_list_length_pctls[101]; // Size of Aho-Corasick transition & match tables. uint32_t ac_tables_size; }; // // YR_PROFILING_INFO contains profiling information for a rule. // struct YR_PROFILING_INFO { // Number of times that some atom belonging to the rule matched. Each // matching atom means a potential string match that needs to be verified. uint32_t atom_matches; // Amount of time (in nanoseconds) spent verifying atom matches for // determining if the corresponding string actually matched or not. This // time is not measured for all atom matches, only 1 out of 1024 matches // are actually measured. uint64_t match_time; // Amount of time (in nanoseconds) spent evaluating the rule condition. uint64_t exec_time; }; //////////////////////////////////////////////////////////////////////////////// // YR_RULE_PROFILING_INFO is the structure returned by // yr_scanner_get_profiling_info // struct YR_RULE_PROFILING_INFO { YR_RULE* rule; uint64_t cost; }; typedef const uint8_t* (*YR_MEMORY_BLOCK_FETCH_DATA_FUNC)( YR_MEMORY_BLOCK* self); typedef YR_MEMORY_BLOCK* (*YR_MEMORY_BLOCK_ITERATOR_FUNC)( YR_MEMORY_BLOCK_ITERATOR* self); typedef uint64_t (*YR_MEMORY_BLOCK_ITERATOR_SIZE_FUNC)( YR_MEMORY_BLOCK_ITERATOR* self); struct YR_MEMORY_BLOCK { size_t size; uint64_t base; void* context; YR_MEMORY_BLOCK_FETCH_DATA_FUNC fetch_data; }; YR_API const uint8_t* yr_fetch_block_data(YR_MEMORY_BLOCK* self); /////////////////////////////////////////////////////////////////////////////// // YR_MEMORY_BLOCK_ITERATOR represents an iterator that returns a series of // memory blocks to be scanned by yr_scanner_scan_mem_blocks. The iterator have // pointers to three functions: "first", "next" and "file_size". The "first" // function is invoked for retrieving the first memory block, followed by calls // to "next" for retrieving the following blocks until "next" returns a NULL // pointer. The "file_size" function is called for obtaining the size of the // file. struct YR_MEMORY_BLOCK_ITERATOR { // A pointer that can be used by specific implementations of an iterator for // storing the iterator's state. void* context; // Pointers to functions for iterating over the memory blocks. YR_MEMORY_BLOCK_ITERATOR_FUNC first; YR_MEMORY_BLOCK_ITERATOR_FUNC next; // Pointer to a function that returns the file size as computed by the // iterator. This is a the size returned by the filesize keyword in YARA // rules. If this pointer is NULL the file size will be undefined. YR_MEMORY_BLOCK_ITERATOR_SIZE_FUNC file_size; // Error occurred during the last call to "first" or "next" functions. These // functions must set the value of last_error to ERROR_SUCCESS or to some // other error code if appropriate. Alternatively, last_error can be set to // ERROR_SUCCESS before using the iterator and changed by "first" or "next" // only when they want to report an error. int last_error; }; typedef int (*YR_CALLBACK_FUNC)( YR_SCAN_CONTEXT* context, int message, void* message_data, void* user_data); struct YR_SCAN_CONTEXT { // File size of the file being scanned. uint64_t file_size; // Entry point of the file being scanned, if the file is PE or ELF. uint64_t entry_point; // Scanning flags. int flags; // Canary value used for preventing hand-crafted objects from being embedded // in compiled rules and used to exploit YARA. The canary value is initialized // to a random value and is subsequently set to all objects created by // yr_object_create. The canary is verified when objects are used by // yr_execute_code. int canary; // Scan timeout in nanoseconds. uint64_t timeout; // Pointer to user-provided data passed to the callback function. void* user_data; // Pointer to the user-provided callback function that is called when an // event occurs during the scan (a rule matching, a module being loaded, etc) YR_CALLBACK_FUNC callback; // Pointer to the YR_RULES object associated to this scan context. YR_RULES* rules; // Pointer to the YR_STRING causing the most recent scan error. YR_STRING* last_error_string; // Pointer to the iterator used for scanning YR_MEMORY_BLOCK_ITERATOR* iterator; // Pointer to a table mapping identifiers to YR_OBJECT structures. This table // contains entries for external variables and modules. YR_HASH_TABLE* objects_table; // Notebook used for storing YR_MATCH structures associated to the matches // found. YR_NOTEBOOK* matches_notebook; // Stopwatch used for measuring the time elapsed during the scan. YR_STOPWATCH stopwatch; // Fiber pool used by yr_re_exec. RE_FIBER_POOL re_fiber_pool; // Pool used by yr_re_fast_exec. RE_FAST_EXEC_POSITION_POOL re_fast_exec_position_pool; // A bitmap with one bit per rule, bit N is set when the rule with index N // has matched. YR_BITMASK* rule_matches_flags; // A bitmap with one bit per namespace, bit N is set if the namespace with // index N has some global rule that is not satisfied. YR_BITMASK* ns_unsatisfied_flags; // A bitmap with one bit per string, bit N is set if the string with index // N has too many matches. YR_BITMASK* strings_temp_disabled; // Array with pointers to lists of matches. Item N in the array has the // list of matches for string with index N. YR_MATCHES* matches; // "unconfirmed_matches" is like "matches" but for strings that are part of // a chain. Let's suppose that the string S is split in two chained strings // S1 <- S2. When a match is found for S1, we can't be sure that S matches // until a match for S2 is found (within the range defined by chain_gap_min // and chain_gap_max), so the matches for S1 are put in "unconfirmed_matches" // until they can be confirmed or discarded. YR_MATCHES* unconfirmed_matches; // A bitmap with one bit per rule, bit N is set if the corresponding rule // must evaluated. YR_BITMASK* required_eval; // profiling_info is a pointer to an array of YR_PROFILING_INFO structures, // one per rule. Entry N has the profiling information for rule with index N. YR_PROFILING_INFO* profiling_info; }; union YR_VALUE { int64_t i; double d; void* p; YR_OBJECT* o; YR_STRING* s; YR_ITERATOR* it; SIZED_STRING* ss; RE* re; }; struct YR_VALUE_STACK { uint32_t sp; uint32_t capacity; YR_VALUE* items; }; #define OBJECT_COMMON_FIELDS \ int canary; \ int8_t type; \ const char* identifier; \ YR_OBJECT* parent; \ void* data; struct YR_OBJECT { OBJECT_COMMON_FIELDS YR_VALUE value; }; struct YR_OBJECT_STRUCTURE { OBJECT_COMMON_FIELDS YR_STRUCTURE_MEMBER* members; }; struct YR_OBJECT_ARRAY { OBJECT_COMMON_FIELDS YR_OBJECT* prototype_item; YR_ARRAY_ITEMS* items; }; struct YR_OBJECT_DICTIONARY { OBJECT_COMMON_FIELDS YR_OBJECT* prototype_item; YR_DICTIONARY_ITEMS* items; }; typedef int (*YR_MODULE_FUNC)( YR_VALUE* args, YR_SCAN_CONTEXT* context, YR_OBJECT_FUNCTION* function_obj); struct YR_OBJECT_FUNCTION { OBJECT_COMMON_FIELDS YR_OBJECT* return_obj; struct { const char* arguments_fmt; YR_MODULE_FUNC code; } prototypes[YR_MAX_OVERLOADED_FUNCTIONS]; }; #define object_as_structure(obj) ((YR_OBJECT_STRUCTURE*) (obj)) #define object_as_array(obj) ((YR_OBJECT_ARRAY*) (obj)) #define object_as_dictionary(obj) ((YR_OBJECT_DICTIONARY*) (obj)) #define object_as_function(obj) ((YR_OBJECT_FUNCTION*) (obj)) struct YR_STRUCTURE_MEMBER { YR_OBJECT* object; YR_STRUCTURE_MEMBER* next; }; struct YR_ARRAY_ITEMS { // Capacity is the size of the objects array. int capacity; // Length is determined by the last element in the array. If the index of the // last element is N, then length is N+1 because indexes start at 0. int length; YR_OBJECT* objects[1]; }; struct YR_DICTIONARY_ITEMS { int used; int free; struct { SIZED_STRING* key; YR_OBJECT* obj; } objects[1]; }; // Iterators are used in loops of the form: // // for in : ( ) // // The YR_ITERATOR struct abstracts the many different types of objects that // can be iterated. Each type of iterator must provide a "next" function which // is called multiple times for retrieving elements from the iterator. This // function is responsible for pushing the next item in the stack and a boolean // indicating if the end of the iterator has been reached. The boolean must be // pushed first, so that the next item is in the top of the stack when the // function returns. // // +------------+ // | next item | <- top of the stack // +------------+ // | false | <- false indicates that there are more items // +------------+ // | . . . | // // The boolean shouldn't be true if the next item was pushed in the stack, it // can be true only when all the items have been returned in previous calls, // in which case the value for the next item should be YR_UNDEFINED. The stack // should look like this after the last call to "next": // // +------------+ // | undefined | <- next item is undefined. // +------------+ // | true | <- true indicates that are no more items. // +------------+ // | . . . | // // We can't use the YR_UNDEFINED value in the stack as an indicator of the end // of the iterator, because it's legitimate for an iterator to return // YR_UNDEFINED items in the middle of the iteration. // // The "next" function should return ERROR_SUCCESS if everything went fine or // an error code in case of error. typedef int (*YR_ITERATOR_NEXT_FUNC)(YR_ITERATOR* self, YR_VALUE_STACK* stack); struct YR_ARRAY_ITERATOR { YR_OBJECT* array; int index; }; struct YR_DICT_ITERATOR { YR_OBJECT* dict; int index; }; struct YR_INT_RANGE_ITERATOR { int64_t next; int64_t last; }; struct YR_INT_ENUM_ITERATOR { int64_t next; int64_t count; int64_t items[1]; }; struct YR_STRING_SET_ITERATOR { int64_t count; int64_t index; YR_STRING* strings[1]; }; struct YR_TEXT_STRING_SET_ITERATOR { int64_t count; int64_t index; SIZED_STRING* strings[1]; }; struct YR_ITERATOR { // Index of the next function within the iter_next_func_table global array. uint8_t next_func_idx; union { struct YR_ARRAY_ITERATOR array_it; struct YR_DICT_ITERATOR dict_it; struct YR_INT_RANGE_ITERATOR int_range_it; struct YR_INT_ENUM_ITERATOR int_enum_it; struct YR_STRING_SET_ITERATOR string_set_it; struct YR_TEXT_STRING_SET_ITERATOR text_string_set_it; }; }; #endif yara-4.5.3/libyara/include/yara/unaligned.h000066400000000000000000000055551501365277300206230ustar00rootroot00000000000000/* Copyright (c) 2016. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_UNALIGNED_H #define YR_UNALIGNED_H #include #pragma pack(push) #pragma pack(1) typedef struct { uint16_t val; } uint16_una_t; typedef struct { uint32_t val; } uint32_una_t; typedef struct { uint64_t val; } uint64_una_t; typedef struct { int16_t val; } int16_una_t; typedef struct { int32_t val; } int32_una_t; typedef struct { int64_t val; } int64_una_t; typedef struct { char *val; } charp_una_t; #pragma pack(pop) static inline uint16_t yr_unaligned_u16(const void *ptr) { const uint16_una_t *tmp = (const uint16_una_t *) ptr; return tmp->val; } static inline uint32_t yr_unaligned_u32(const void *ptr) { const uint32_una_t *tmp = (const uint32_una_t *) ptr; return tmp->val; } static inline uint64_t yr_unaligned_u64(const void *ptr) { const uint64_una_t *tmp = (const uint64_una_t *) ptr; return tmp->val; } static inline uint16_t yr_unaligned_i16(const void *ptr) { const int16_una_t *tmp = (const int16_una_t *) ptr; return tmp->val; } static inline uint32_t yr_unaligned_i32(const void *ptr) { const int32_una_t *tmp = (const int32_una_t *) ptr; return tmp->val; } static inline uint64_t yr_unaligned_i64(const void *ptr) { const int64_una_t *tmp = (const int64_una_t *) ptr; return tmp->val; } static inline char *yr_unaligned_char_ptr(const void *ptr) { const charp_una_t *tmp = (const charp_una_t *) ptr; return tmp->val; } #endif yara-4.5.3/libyara/include/yara/utils.h000066400000000000000000000122601501365277300200040ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef YR_UTILS_H #define YR_UTILS_H #include #ifndef NULL #define NULL 0 #endif #if defined(HAVE_STDBOOL_H) || (defined(_MSC_VER) && _MSC_VER >= 1800) #include #else #ifndef __cplusplus #define bool _Bool #define true 1 #define false 0 #endif /* __cplusplus */ #endif #ifdef __cplusplus #define EXTERNC extern "C" #else #define EXTERNC #endif #if defined(_WIN32) || defined(__CYGWIN__) #ifdef YR_BUILDING_DLL #ifdef __GNUC__ #define YR_API EXTERNC __attribute__((dllexport)) #define YR_DEPRECATED_API EXTERNC __attribute__((deprecated)) #define YR_DEPRECATED(statement) statement __attribute__((deprecated)) #else #define YR_API EXTERNC __declspec(dllexport) #define YR_DEPRECATED_API EXTERNC __declspec(deprecated) #define YR_DEPRECATED(statement) __declspec(deprecated) statement #endif #elif defined(YR_IMPORTING_DLL) #ifdef __GNUC__ #define YR_API EXTERNC __attribute__((dllimport)) #define YR_DEPRECATED_API EXTERNC __attribute__((deprecated)) #define YR_DEPRECATED(statement) statement __attribute__((deprecated)) #else #define YR_API EXTERNC __declspec(dllimport) #define YR_DEPRECATED_API EXTERNC __declspec(deprecated) #define YR_DEPRECATED(statement) __declspec(deprecated) statement #endif #else #define YR_API EXTERNC #define YR_DEPRECATED_API EXTERNC #define YR_DEPRECATED(statement) statement #endif #else #if __GNUC__ >= 4 #define YR_API EXTERNC __attribute__((visibility("default"))) #define YR_DEPRECATED_API YR_API __attribute__((deprecated)) #define YR_DEPRECATED(statement) statement __attribute__((deprecated)) #else #define YR_API EXTERNC #define YR_DEPRECATED_API EXTERNC #define YR_DEPRECATED(statement) statement #endif #endif #if defined(__GNUC__) #define YR_ALIGN(n) __attribute__((aligned(n))) #elif defined(_MSC_VER) #define YR_ALIGN(n) __declspec(align(n)) #else #define YR_ALIGN(n) #endif #if defined(__GNUC__) #define YR_PRINTF_LIKE(x, y) __attribute__((format(printf, x, y))) #else #define YR_PRINTF_LIKE(x, y) #endif #define yr_min(x, y) (((x) < (y)) ? (x) : (y)) #define yr_max(x, y) (((x) > (y)) ? (x) : (y)) #define yr_swap(x, y, T) \ do \ { \ T temp = x; \ x = y; \ y = temp; \ } while (0) #ifdef NDEBUG #define assertf(expr, msg, ...) ((void) 0) #else #include #define assertf(expr, msg, ...) \ if (!(expr)) \ { \ fprintf(stderr, "%s:%d: " msg "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ abort(); \ } #endif // Set, unset, and test bits in an array of unsigned characters by integer // index. The underlying array must be of type char or unsigned char to // ensure compatibility with the CHAR_BIT constant used in these definitions. #define YR_BITARRAY_SET(uchar_array_base, bitnum) \ (((uchar_array_base)[(bitnum) / CHAR_BIT]) = \ ((uchar_array_base)[(bitnum) / CHAR_BIT] | \ (1 << ((bitnum) % CHAR_BIT)))) #define YR_BITARRAY_UNSET(uchar_array_base, bitnum) \ (((uchar_array_base)[(bitnum) / CHAR_BIT]) = \ ((uchar_array_base)[(bitnum) / CHAR_BIT] & \ (~(1 << ((bitnum) % CHAR_BIT))))) #define YR_BITARRAY_TEST(uchar_array_base, bitnum) \ (((uchar_array_base)[(bitnum) / CHAR_BIT] & (1 << ((bitnum) % CHAR_BIT))) != \ 0) #define YR_BITARRAY_NCHARS(bitnum) (((bitnum) + (CHAR_BIT - 1)) / CHAR_BIT) #endif yara-4.5.3/libyara/lexer.c000066400000000000000000003010451501365277300154010ustar00rootroot00000000000000#line 1 "libyara/lexer.c" #line 3 "libyara/lexer.c" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 6 #define YY_FLEX_SUBMINOR_VERSION 4 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif #ifdef yy_create_buffer #define yara_yy_create_buffer_ALREADY_DEFINED #else #define yy_create_buffer yara_yy_create_buffer #endif #ifdef yy_delete_buffer #define yara_yy_delete_buffer_ALREADY_DEFINED #else #define yy_delete_buffer yara_yy_delete_buffer #endif #ifdef yy_scan_buffer #define yara_yy_scan_buffer_ALREADY_DEFINED #else #define yy_scan_buffer yara_yy_scan_buffer #endif #ifdef yy_scan_string #define yara_yy_scan_string_ALREADY_DEFINED #else #define yy_scan_string yara_yy_scan_string #endif #ifdef yy_scan_bytes #define yara_yy_scan_bytes_ALREADY_DEFINED #else #define yy_scan_bytes yara_yy_scan_bytes #endif #ifdef yy_init_buffer #define yara_yy_init_buffer_ALREADY_DEFINED #else #define yy_init_buffer yara_yy_init_buffer #endif #ifdef yy_flush_buffer #define yara_yy_flush_buffer_ALREADY_DEFINED #else #define yy_flush_buffer yara_yy_flush_buffer #endif #ifdef yy_load_buffer_state #define yara_yy_load_buffer_state_ALREADY_DEFINED #else #define yy_load_buffer_state yara_yy_load_buffer_state #endif #ifdef yy_switch_to_buffer #define yara_yy_switch_to_buffer_ALREADY_DEFINED #else #define yy_switch_to_buffer yara_yy_switch_to_buffer #endif #ifdef yypush_buffer_state #define yara_yypush_buffer_state_ALREADY_DEFINED #else #define yypush_buffer_state yara_yypush_buffer_state #endif #ifdef yypop_buffer_state #define yara_yypop_buffer_state_ALREADY_DEFINED #else #define yypop_buffer_state yara_yypop_buffer_state #endif #ifdef yyensure_buffer_stack #define yara_yyensure_buffer_stack_ALREADY_DEFINED #else #define yyensure_buffer_stack yara_yyensure_buffer_stack #endif #ifdef yylex #define yara_yylex_ALREADY_DEFINED #else #define yylex yara_yylex #endif #ifdef yyrestart #define yara_yyrestart_ALREADY_DEFINED #else #define yyrestart yara_yyrestart #endif #ifdef yylex_init #define yara_yylex_init_ALREADY_DEFINED #else #define yylex_init yara_yylex_init #endif #ifdef yylex_init_extra #define yara_yylex_init_extra_ALREADY_DEFINED #else #define yylex_init_extra yara_yylex_init_extra #endif #ifdef yylex_destroy #define yara_yylex_destroy_ALREADY_DEFINED #else #define yylex_destroy yara_yylex_destroy #endif #ifdef yyget_debug #define yara_yyget_debug_ALREADY_DEFINED #else #define yyget_debug yara_yyget_debug #endif #ifdef yyset_debug #define yara_yyset_debug_ALREADY_DEFINED #else #define yyset_debug yara_yyset_debug #endif #ifdef yyget_extra #define yara_yyget_extra_ALREADY_DEFINED #else #define yyget_extra yara_yyget_extra #endif #ifdef yyset_extra #define yara_yyset_extra_ALREADY_DEFINED #else #define yyset_extra yara_yyset_extra #endif #ifdef yyget_in #define yara_yyget_in_ALREADY_DEFINED #else #define yyget_in yara_yyget_in #endif #ifdef yyset_in #define yara_yyset_in_ALREADY_DEFINED #else #define yyset_in yara_yyset_in #endif #ifdef yyget_out #define yara_yyget_out_ALREADY_DEFINED #else #define yyget_out yara_yyget_out #endif #ifdef yyset_out #define yara_yyset_out_ALREADY_DEFINED #else #define yyset_out yara_yyset_out #endif #ifdef yyget_leng #define yara_yyget_leng_ALREADY_DEFINED #else #define yyget_leng yara_yyget_leng #endif #ifdef yyget_text #define yara_yyget_text_ALREADY_DEFINED #else #define yyget_text yara_yyget_text #endif #ifdef yyget_lineno #define yara_yyget_lineno_ALREADY_DEFINED #else #define yyget_lineno yara_yyget_lineno #endif #ifdef yyset_lineno #define yara_yyset_lineno_ALREADY_DEFINED #else #define yyset_lineno yara_yyset_lineno #endif #ifdef yyget_column #define yara_yyget_column_ALREADY_DEFINED #else #define yyget_column yara_yyget_column #endif #ifdef yyset_column #define yara_yyset_column_ALREADY_DEFINED #else #define yyset_column yara_yyset_column #endif #ifdef yywrap #define yara_yywrap_ALREADY_DEFINED #else #define yywrap yara_yywrap #endif #ifdef yyget_lval #define yara_yyget_lval_ALREADY_DEFINED #else #define yyget_lval yara_yyget_lval #endif #ifdef yyset_lval #define yara_yyset_lval_ALREADY_DEFINED #else #define yyset_lval yara_yyset_lval #endif #ifdef yyalloc #define yara_yyalloc_ALREADY_DEFINED #else #define yyalloc yara_yyalloc #endif #ifdef yyrealloc #define yara_yyrealloc_ALREADY_DEFINED #else #define yyrealloc yara_yyrealloc #endif #ifdef yyfree #define yara_yyfree_ALREADY_DEFINED #else #define yyfree yara_yyfree #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #ifndef SIZE_MAX #define SIZE_MAX (~(size_t)0) #endif #endif /* ! C99 */ #endif /* ! FLEXINT_H */ /* begin standard C++ headers. */ /* TODO: this is always defined, so inline it */ #define yyconst const #if defined(__GNUC__) && __GNUC__ >= 3 #define yynoreturn __attribute__((__noreturn__)) #else #define yynoreturn #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an * integer in range [0..255] for use as an array index. */ #define YY_SC_TO_UI(c) ((YY_CHAR) (c)) /* An opaque pointer. */ #ifndef YY_TYPEDEF_YY_SCANNER_T #define YY_TYPEDEF_YY_SCANNER_T typedef void* yyscan_t; #endif /* For convenience, these vars (plus the bison vars far below) are macros in the reentrant scanner. */ #define yyin yyg->yyin_r #define yyout yyg->yyout_r #define yyextra yyg->yyextra_r #define yyleng yyg->yyleng_r #define yytext yyg->yytext_r #define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) #define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) #define yy_flex_debug yyg->yy_flex_debug_r /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN yyg->yy_start = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START ((yyg->yy_start - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart( yyin , yyscanner ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k. * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. * Ditto for the __ia64__ case accordingly. */ #define YY_BUF_SIZE 32768 #else #define YY_BUF_SIZE 16384 #endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires * access to the local variable yy_act. Since yyless() is a macro, it would break * existing scanners that call yyless() from OUTSIDE yylex. * One obvious solution it to make yy_act a global. I tried that, and saw * a 5% performance hit in a non-yylineno scanner, because yy_act is * normally declared as a register variable-- so it is not worth it. */ #define YY_LESS_LINENO(n) \ do { \ int yyl;\ for ( yyl = n; yyl < yyleng; ++yyl )\ if ( yytext[yyl] == '\n' )\ --yylineno;\ }while(0) #define YY_LINENO_REWIND_TO(dst) \ do {\ const char *p;\ for ( p = yy_cp-1; p >= (dst); --p)\ if ( *p == '\n' )\ --yylineno;\ }while(0) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = yyg->yy_hold_char; \ YY_RESTORE_YY_MORE_OFFSET \ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] void yyrestart ( FILE *input_file , yyscan_t yyscanner ); void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); void yypop_buffer_state ( yyscan_t yyscanner ); static void yyensure_buffer_stack ( yyscan_t yyscanner ); static void yy_load_buffer_state ( yyscan_t yyscanner ); static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); #define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); void *yyalloc ( yy_size_t , yyscan_t yyscanner ); void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); void yyfree ( void * , yyscan_t yyscanner ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (yyscanner); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (yyscanner); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ #define yara_yywrap(yyscanner) (/*CONSTCOND*/1) #define YY_SKIP_YYWRAP typedef flex_uint8_t YY_CHAR; typedef int yy_state_type; #define yytext_ptr yytext_r static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); static int yy_get_next_buffer ( yyscan_t yyscanner ); static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ yyg->yytext_ptr = yy_bp; \ yyleng = (int) (yy_cp - yy_bp); \ yyg->yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; #define YY_NUM_RULES 86 #define YY_END_OF_BUFFER 87 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static const flex_int16_t yy_accept[295] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 85, 84, 84, 59, 81, 57, 56, 85, 82, 62, 62, 2, 85, 3, 58, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 85, 73, 74, 66, 86, 79, 80, 76, 86, 53, 54, 50, 50, 59, 7, 57, 55, 56, 1, 48, 51, 0, 62, 0, 0, 0, 0, 8, 4, 6, 5, 9, 58, 61, 61, 61, 61, 28, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 29, 61, 61, 61, 61, 30, 27, 61, 61, 61, 61, 61, 61, 61, 61, 0, 0, 73, 75, 70, 71, 69, 68, 67, 75, 79, 76, 76, 78, 77, 53, 49, 51, 63, 62, 65, 64, 33, 26, 34, 61, 61, 61, 61, 61, 61, 61, 61, 32, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 25, 61, 61, 61, 61, 61, 61, 61, 61, 17, 83, 0, 0, 0, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 60, 61, 61, 13, 61, 35, 61, 12, 61, 61, 31, 23, 16, 0, 0, 0, 0, 72, 15, 61, 61, 61, 61, 61, 61, 24, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 18, 61, 61, 61, 61, 61, 61, 61, 11, 61, 61, 61, 46, 61, 60, 61, 61, 21, 61, 61, 61, 61, 61, 61, 47, 61, 61, 61, 61, 61, 61, 45, 61, 61, 38, 10, 61, 14, 61, 61, 39, 41, 61, 37, 20, 61, 61, 0, 61, 61, 61, 22, 61, 42, 44, 52, 61, 61, 19, 36, 61, 40, 43, 0 } ; static const YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 5, 6, 7, 8, 1, 1, 1, 9, 9, 10, 1, 1, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 18, 20, 21, 1, 1, 22, 23, 24, 9, 25, 26, 27, 26, 26, 26, 26, 28, 28, 28, 28, 29, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 9, 31, 9, 1, 32, 1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 28, 28, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 9, 58, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static const YY_CHAR yy_meta[59] = { 0, 1, 2, 3, 2, 1, 4, 1, 1, 2, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1, 9, 1, 1, 10, 10, 11, 12, 12, 13, 11, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, 11, 11, 11, 11, 11, 11, 11, 11, 12, 11, 11, 1, 1 } ; static const flex_int16_t yy_base[318] = { 0, 0, 0, 56, 57, 58, 61, 502, 501, 496, 495, 504, 509, 509, 509, 480, 509, 0, 492, 490, 55, 55, 61, 46, 477, 51, 0, 0, 52, 466, 453, 460, 452, 62, 453, 73, 43, 449, 33, 445, 441, 441, 38, 449, 448, 443, 475, 0, 509, 509, 87, 0, 509, 56, 474, 0, 509, 509, 473, 461, 509, 0, 509, 473, 509, 509, 0, 0, 0, 455, 454, 110, 0, 509, 509, 509, 509, 509, 0, 0, 438, 43, 444, 0, 429, 433, 438, 83, 433, 432, 425, 430, 426, 425, 67, 423, 86, 418, 417, 416, 95, 0, 0, 424, 422, 99, 426, 411, 417, 424, 411, 92, 128, 0, 509, 509, 509, 509, 509, 509, 0, 0, 409, 509, 509, 509, 0, 509, 0, 0, 509, 138, 0, 0, 0, 0, 416, 419, 84, 414, 405, 405, 403, 414, 0, 408, 415, 404, 411, 395, 400, 402, 128, 410, 407, 408, 407, 402, 0, 386, 400, 388, 394, 391, 396, 382, 394, 0, 509, 420, 426, 0, 387, 408, 385, 392, 380, 370, 367, 384, 371, 366, 385, 367, 367, 382, 366, 362, 393, 396, 376, 361, 368, 0, 358, 0, 373, 0, 355, 360, 0, 0, 0, 393, 148, 399, 131, 509, 0, 384, 350, 358, 361, 356, 349, 0, 325, 318, 309, 306, 272, 275, 263, 253, 251, 234, 244, 243, 229, 224, 229, 212, 223, 219, 225, 206, 209, 197, 200, 0, 147, 146, 137, 0, 148, 0, 135, 134, 0, 145, 128, 131, 138, 133, 128, 0, 136, 134, 137, 137, 128, 121, 0, 168, 116, 0, 0, 127, 0, 131, 122, 0, 0, 121, 0, 0, 115, 122, 157, 120, 99, 109, 0, 62, 0, 0, 509, 49, 43, 0, 0, 42, 0, 0, 509, 189, 202, 215, 228, 234, 239, 247, 254, 259, 264, 275, 285, 297, 310, 322, 335, 348, 69, 354, 357, 367, 380, 386 } ; static const flex_int16_t yy_def[318] = { 0, 294, 1, 295, 295, 296, 296, 297, 297, 298, 298, 294, 294, 294, 294, 299, 294, 300, 301, 294, 294, 302, 302, 294, 294, 294, 303, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 305, 306, 294, 294, 307, 308, 294, 294, 309, 310, 294, 294, 294, 299, 294, 300, 294, 301, 294, 294, 311, 312, 22, 294, 294, 294, 313, 294, 294, 294, 294, 294, 303, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 305, 294, 306, 294, 294, 294, 294, 294, 294, 314, 308, 294, 294, 294, 294, 310, 294, 311, 312, 294, 294, 313, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 294, 315, 316, 317, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 315, 315, 316, 305, 294, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 294, 304, 304, 304, 304, 304, 304, 304, 294, 304, 304, 304, 304, 304, 304, 304, 0, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294 } ; static const flex_int16_t yy_nxt[568] = { 0, 12, 13, 14, 13, 15, 16, 17, 18, 12, 12, 19, 20, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 24, 25, 26, 27, 27, 27, 27, 27, 12, 27, 28, 29, 30, 31, 32, 33, 34, 27, 35, 27, 36, 37, 38, 39, 27, 40, 41, 42, 43, 27, 44, 45, 27, 27, 46, 12, 48, 48, 52, 49, 49, 52, 65, 67, 66, 73, 74, 53, 101, 67, 53, 76, 77, 98, 129, 106, 134, 99, 102, 293, 292, 69, 70, 107, 50, 50, 54, 69, 70, 54, 115, 80, 88, 81, 122, 135, 291, 71, 82, 83, 89, 112, 123, 294, 90, 93, 72, 94, 148, 290, 91, 149, 294, 95, 96, 116, 140, 174, 151, 97, 131, 131, 131, 131, 131, 131, 131, 156, 117, 161, 141, 175, 118, 152, 119, 169, 157, 170, 120, 188, 112, 189, 158, 289, 162, 190, 288, 168, 131, 131, 131, 131, 131, 131, 131, 204, 278, 111, 287, 285, 286, 284, 283, 282, 281, 280, 279, 278, 277, 276, 275, 274, 273, 272, 271, 270, 269, 268, 267, 266, 265, 264, 263, 262, 261, 260, 168, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 59, 59, 59, 59, 59, 61, 259, 61, 61, 61, 63, 258, 257, 63, 256, 63, 63, 63, 68, 255, 68, 254, 253, 252, 68, 78, 251, 78, 78, 78, 79, 250, 79, 79, 79, 111, 111, 249, 248, 247, 111, 111, 246, 111, 113, 113, 245, 244, 113, 113, 113, 113, 113, 113, 113, 113, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 121, 121, 243, 121, 121, 121, 242, 121, 121, 121, 121, 121, 124, 124, 241, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 126, 126, 126, 240, 126, 126, 126, 126, 126, 126, 126, 126, 126, 128, 128, 239, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 132, 238, 132, 171, 237, 171, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 207, 236, 207, 235, 234, 233, 232, 231, 206, 204, 230, 229, 228, 227, 226, 225, 224, 190, 190, 223, 222, 221, 220, 219, 218, 217, 216, 215, 214, 213, 212, 211, 210, 209, 208, 206, 204, 202, 152, 201, 200, 199, 198, 197, 196, 195, 194, 193, 192, 191, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 173, 172, 123, 167, 166, 165, 164, 163, 160, 159, 155, 154, 153, 150, 147, 146, 145, 144, 143, 142, 139, 138, 137, 136, 133, 130, 130, 62, 294, 127, 125, 112, 110, 109, 108, 105, 104, 103, 100, 92, 87, 86, 85, 84, 75, 64, 62, 60, 294, 58, 58, 56, 56, 11, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294 } ; static const flex_int16_t yy_chk[568] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 4, 5, 3, 4, 6, 20, 21, 20, 23, 23, 5, 38, 22, 6, 25, 25, 36, 312, 42, 81, 36, 38, 291, 288, 21, 21, 42, 3, 4, 5, 22, 22, 6, 50, 28, 33, 28, 53, 81, 287, 21, 28, 28, 33, 111, 53, 22, 33, 35, 21, 35, 94, 283, 33, 94, 22, 35, 35, 50, 87, 138, 96, 35, 71, 71, 71, 71, 71, 71, 71, 100, 50, 105, 87, 138, 50, 96, 50, 112, 100, 112, 50, 152, 206, 152, 100, 281, 105, 152, 280, 111, 131, 131, 131, 131, 131, 131, 131, 204, 278, 204, 279, 277, 278, 276, 273, 270, 269, 267, 264, 263, 261, 260, 259, 258, 257, 256, 254, 253, 252, 251, 250, 249, 247, 246, 244, 242, 241, 240, 206, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 295, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 296, 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 299, 299, 299, 299, 299, 300, 238, 300, 300, 300, 301, 237, 236, 301, 235, 301, 301, 301, 302, 234, 302, 233, 232, 231, 302, 303, 230, 303, 303, 303, 304, 229, 304, 304, 304, 305, 305, 228, 227, 226, 305, 305, 225, 305, 306, 306, 224, 223, 306, 306, 306, 306, 306, 306, 306, 306, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 307, 308, 308, 222, 308, 308, 308, 221, 308, 308, 308, 308, 308, 309, 309, 220, 309, 309, 309, 309, 309, 309, 309, 309, 309, 309, 310, 310, 310, 219, 310, 310, 310, 310, 310, 310, 310, 310, 310, 311, 311, 218, 311, 311, 311, 311, 311, 311, 311, 311, 311, 311, 313, 217, 313, 314, 216, 314, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 315, 316, 316, 316, 316, 316, 316, 316, 316, 316, 316, 316, 316, 316, 317, 214, 317, 213, 212, 211, 210, 209, 205, 203, 199, 198, 196, 194, 192, 191, 190, 189, 188, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 173, 172, 170, 169, 166, 165, 164, 163, 162, 161, 160, 159, 157, 156, 155, 154, 153, 151, 150, 149, 148, 147, 146, 145, 143, 142, 141, 140, 139, 137, 136, 122, 110, 109, 108, 107, 106, 104, 103, 99, 98, 97, 95, 93, 92, 91, 90, 89, 88, 86, 85, 84, 82, 80, 70, 69, 63, 59, 58, 54, 46, 45, 44, 43, 41, 40, 39, 37, 34, 32, 31, 30, 29, 24, 19, 18, 15, 11, 10, 9, 8, 7, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294 } ; /* Table of booleans, true if rule could match eol. */ static const flex_int32_t yy_rule_can_match_eol[87] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, }; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET #line 1 "libyara/lexer.l" /* Copyright (c) 2007-2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Lexical analyzer for YARA */ #line 33 "libyara/lexer.l" /* Disable warnings for unused functions in this file. As we redefine YY_FATAL_ERROR macro to use our own function yara_yyfatal, the yy_fatal_error function generated by Flex is not actually used, causing a compiler warning. Flex doesn't offer any options to remove the yy_fatal_error function. When they include something like %option noyy_fatal_error as they do with noyywrap then we can remove this pragma. */ #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wunused-function" #endif #include #include #include #include #include #include #if defined(_WIN32) || defined(__CYGWIN__) #include #else #include #include #endif #if defined(_WIN32) #define strtoll _strtoi64 #endif #include #include #include #include #include #include #include #include "grammar.h" #define error(error_code) \ { \ compiler->last_error = error_code; \ yyerror(yyscanner, compiler, NULL); \ yyterminate(); \ } #define syntax_error(error_msg) \ { \ yr_compiler_set_error_extra_info(compiler, error_msg); \ error(ERROR_SYNTAX_ERROR); \ } #define lex_check_space_ok(data, current_size, max_length) \ if (strlen(data) + current_size >= max_length - 1) \ { \ yyerror(yyscanner, compiler, "out of space in lex_buf"); \ yyterminate(); \ } #define yytext_to_buffer \ { \ char *yptr = yytext; \ lex_check_space_ok(yptr, yyextra->lex_buf_len, YR_LEX_BUF_SIZE); \ while(*yptr) \ { \ *yyextra->lex_buf_ptr++ = *yptr++; \ yyextra->lex_buf_len++; \ } \ } #define alloc_sized_string(str, str_len) \ SIZED_STRING* str = (SIZED_STRING*) yr_malloc( \ str_len + sizeof(SIZED_STRING)); \ if (str == NULL) \ { \ yyerror(yyscanner, compiler, "not enough memory"); \ yyterminate(); \ } \ else \ { \ str->length = (uint32_t) (str_len); \ str->flags = 0; \ } \ #ifdef _WIN32 #define snprintf _snprintf #endif static bool is_absolute_path( char* path) { if (path == NULL) return false; #if defined(_WIN32) || defined(__CYGWIN__) return strlen(path) > 2 && path[1] == ':' && (path[2] == '/' || path[2] == '\\'); #else return strlen(path) > 0 && path[0] == '/'; #endif } #line 1033 "libyara/lexer.c" #define YY_NO_UNISTD_H 1 #define YY_NO_INPUT 1 #line 1037 "libyara/lexer.c" #define INITIAL 0 #define str 1 #define regexp 2 #define include 3 #define comment 4 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif /* Holds the entire state of the reentrant scanner. */ struct yyguts_t { /* User-defined. Not touched by flex. */ YY_EXTRA_TYPE yyextra_r; /* The rest are the same as the globals declared in the non-reentrant scanner. */ FILE *yyin_r, *yyout_r; size_t yy_buffer_stack_top; /**< index of top of stack. */ size_t yy_buffer_stack_max; /**< capacity of stack. */ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ char yy_hold_char; int yy_n_chars; int yyleng_r; char *yy_c_buf_p; int yy_init; int yy_start; int yy_did_buffer_switch_on_eof; int yy_start_stack_ptr; int yy_start_stack_depth; int *yy_start_stack; yy_state_type yy_last_accepting_state; char* yy_last_accepting_cpos; int yylineno_r; int yy_flex_debug_r; char *yytext_r; int yy_more_flag; int yy_more_len; YYSTYPE * yylval_r; }; /* end struct yyguts_t */ static int yy_init_globals ( yyscan_t yyscanner ); /* This must go here because YYSTYPE and YYLTYPE are included * from bison output in section 1.*/ # define yylval yyg->yylval_r int yylex_init (yyscan_t* scanner); int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy ( yyscan_t yyscanner ); int yyget_debug ( yyscan_t yyscanner ); void yyset_debug ( int debug_flag , yyscan_t yyscanner ); YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); FILE *yyget_in ( yyscan_t yyscanner ); void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); FILE *yyget_out ( yyscan_t yyscanner ); void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); int yyget_leng ( yyscan_t yyscanner ); char *yyget_text ( yyscan_t yyscanner ); int yyget_lineno ( yyscan_t yyscanner ); void yyset_lineno ( int _line_number , yyscan_t yyscanner ); int yyget_column ( yyscan_t yyscanner ); void yyset_column ( int _column_no , yyscan_t yyscanner ); YYSTYPE * yyget_lval ( yyscan_t yyscanner ); void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap ( yyscan_t yyscanner ); #else extern int yywrap ( yyscan_t yyscanner ); #endif #endif #ifndef YY_NO_UNPUT #endif #ifndef yytext_ptr static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen ( const char * , yyscan_t yyscanner); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput ( yyscan_t yyscanner ); #else static int input ( yyscan_t yyscanner ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k */ #define YY_READ_BUF_SIZE 16384 #else #define YY_READ_BUF_SIZE 8192 #endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ int n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex \ (YYSTYPE * yylval_param , yyscan_t yyscanner); #define YY_DECL int yylex \ (YYSTYPE * yylval_param , yyscan_t yyscanner) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { yy_state_type yy_current_state; char *yy_cp, *yy_bp; int yy_act; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yylval = yylval_param; if ( !yyg->yy_init ) { yyg->yy_init = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! yyg->yy_start ) yyg->yy_start = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (yyscanner); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); } yy_load_buffer_state( yyscanner ); } { #line 163 "libyara/lexer.l" #line 1316 "libyara/lexer.c" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { yy_cp = yyg->yy_c_buf_p; /* Support of yytext. */ *yy_cp = yyg->yy_hold_char; /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = yyg->yy_start; yy_match: do { YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 295 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } while ( yy_current_state != 294 ); yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; yy_find_action: yy_act = yy_accept[yy_current_state]; YY_DO_BEFORE_ACTION; if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) { int yyl; for ( yyl = 0; yyl < yyleng; ++yyl ) if ( yytext[yyl] == '\n' ) do{ yylineno++; yycolumn=0; }while(0) ; } do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = yyg->yy_hold_char; yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; goto yy_find_action; case 1: YY_RULE_SETUP #line 165 "libyara/lexer.l" { return _DOT_DOT_; } YY_BREAK case 2: YY_RULE_SETUP #line 166 "libyara/lexer.l" { return _LT_; } YY_BREAK case 3: YY_RULE_SETUP #line 167 "libyara/lexer.l" { return _GT_; } YY_BREAK case 4: YY_RULE_SETUP #line 168 "libyara/lexer.l" { return _LE_; } YY_BREAK case 5: YY_RULE_SETUP #line 169 "libyara/lexer.l" { return _GE_; } YY_BREAK case 6: YY_RULE_SETUP #line 170 "libyara/lexer.l" { return _EQ_; } YY_BREAK case 7: YY_RULE_SETUP #line 171 "libyara/lexer.l" { return _NEQ_; } YY_BREAK case 8: YY_RULE_SETUP #line 172 "libyara/lexer.l" { return _SHIFT_LEFT_; } YY_BREAK case 9: YY_RULE_SETUP #line 173 "libyara/lexer.l" { return _SHIFT_RIGHT_; } YY_BREAK case 10: YY_RULE_SETUP #line 174 "libyara/lexer.l" { return _PRIVATE_; } YY_BREAK case 11: YY_RULE_SETUP #line 175 "libyara/lexer.l" { return _GLOBAL_; } YY_BREAK case 12: YY_RULE_SETUP #line 176 "libyara/lexer.l" { return _RULE_; } YY_BREAK case 13: YY_RULE_SETUP #line 177 "libyara/lexer.l" { return _META_; } YY_BREAK case 14: YY_RULE_SETUP #line 178 "libyara/lexer.l" { return _STRINGS_; } YY_BREAK case 15: YY_RULE_SETUP #line 179 "libyara/lexer.l" { return _ASCII_; } YY_BREAK case 16: YY_RULE_SETUP #line 180 "libyara/lexer.l" { return _WIDE_; } YY_BREAK case 17: YY_RULE_SETUP #line 181 "libyara/lexer.l" { return _XOR_; } YY_BREAK case 18: YY_RULE_SETUP #line 182 "libyara/lexer.l" { return _BASE64_; } YY_BREAK case 19: YY_RULE_SETUP #line 183 "libyara/lexer.l" { return _BASE64_WIDE_; } YY_BREAK case 20: YY_RULE_SETUP #line 184 "libyara/lexer.l" { return _FULLWORD_; } YY_BREAK case 21: YY_RULE_SETUP #line 185 "libyara/lexer.l" { return _NOCASE_; } YY_BREAK case 22: YY_RULE_SETUP #line 186 "libyara/lexer.l" { return _CONDITION_; } YY_BREAK case 23: YY_RULE_SETUP #line 187 "libyara/lexer.l" { return _TRUE_; } YY_BREAK case 24: YY_RULE_SETUP #line 188 "libyara/lexer.l" { return _FALSE_; } YY_BREAK case 25: YY_RULE_SETUP #line 189 "libyara/lexer.l" { return _NOT_; } YY_BREAK case 26: YY_RULE_SETUP #line 190 "libyara/lexer.l" { return _AND_; } YY_BREAK case 27: YY_RULE_SETUP #line 191 "libyara/lexer.l" { return _OR_; } YY_BREAK case 28: YY_RULE_SETUP #line 192 "libyara/lexer.l" { return _AT_; } YY_BREAK case 29: YY_RULE_SETUP #line 193 "libyara/lexer.l" { return _IN_; } YY_BREAK case 30: YY_RULE_SETUP #line 194 "libyara/lexer.l" { return _OF_; } YY_BREAK case 31: YY_RULE_SETUP #line 195 "libyara/lexer.l" { return _THEM_; } YY_BREAK case 32: YY_RULE_SETUP #line 196 "libyara/lexer.l" { return _FOR_; } YY_BREAK case 33: YY_RULE_SETUP #line 197 "libyara/lexer.l" { return _ALL_; } YY_BREAK case 34: YY_RULE_SETUP #line 198 "libyara/lexer.l" { return _ANY_; } YY_BREAK case 35: YY_RULE_SETUP #line 199 "libyara/lexer.l" { return _NONE_; } YY_BREAK case 36: YY_RULE_SETUP #line 200 "libyara/lexer.l" { return _ENTRYPOINT_; } YY_BREAK case 37: YY_RULE_SETUP #line 201 "libyara/lexer.l" { return _FILESIZE_; } YY_BREAK case 38: YY_RULE_SETUP #line 202 "libyara/lexer.l" { return _MATCHES_; } YY_BREAK case 39: YY_RULE_SETUP #line 203 "libyara/lexer.l" { return _CONTAINS_; } YY_BREAK case 40: YY_RULE_SETUP #line 204 "libyara/lexer.l" { return _STARTSWITH_; } YY_BREAK case 41: YY_RULE_SETUP #line 205 "libyara/lexer.l" { return _ENDSWITH_; } YY_BREAK case 42: YY_RULE_SETUP #line 206 "libyara/lexer.l" { return _ICONTAINS_; } YY_BREAK case 43: YY_RULE_SETUP #line 207 "libyara/lexer.l" { return _ISTARTSWITH_; } YY_BREAK case 44: YY_RULE_SETUP #line 208 "libyara/lexer.l" { return _IENDSWITH_; } YY_BREAK case 45: YY_RULE_SETUP #line 209 "libyara/lexer.l" { return _IEQUALS_; } YY_BREAK case 46: YY_RULE_SETUP #line 210 "libyara/lexer.l" { return _IMPORT_; } YY_BREAK case 47: YY_RULE_SETUP #line 211 "libyara/lexer.l" { return _DEFINED_; } YY_BREAK case 48: YY_RULE_SETUP #line 214 "libyara/lexer.l" { BEGIN(comment); } YY_BREAK case 49: YY_RULE_SETUP #line 215 "libyara/lexer.l" { BEGIN(INITIAL); } YY_BREAK case 50: /* rule 50 can match eol */ YY_RULE_SETUP #line 216 "libyara/lexer.l" { /* skip comments */ } YY_BREAK case 51: YY_RULE_SETUP #line 219 "libyara/lexer.l" { /* skip single-line comments */ } YY_BREAK case 52: YY_RULE_SETUP #line 222 "libyara/lexer.l" { yyextra->lex_buf_ptr = yyextra->lex_buf; yyextra->lex_buf_len = 0; BEGIN(include); } YY_BREAK case 53: /* rule 53 can match eol */ YY_RULE_SETUP #line 229 "libyara/lexer.l" { yytext_to_buffer; } YY_BREAK case 54: YY_RULE_SETUP #line 232 "libyara/lexer.l" { if (compiler->include_callback != NULL) { #ifdef _MSC_VER char* b = NULL; #endif char* s = NULL; char* f; char buffer[1024]; const char* included_rules; char* current_file_name; char* include_path; *yyextra->lex_buf_ptr = '\0'; // null-terminate included file path current_file_name = yr_compiler_get_current_file_name(compiler); if (current_file_name == NULL || compiler->include_callback != _yr_compiler_default_include_callback || is_absolute_path(yyextra->lex_buf)) { include_path = yyextra->lex_buf; } else { strlcpy(buffer, current_file_name, sizeof(buffer)); s = strrchr(buffer, '/'); #ifdef _MSC_VER b = strrchr(buffer, '\\'); // in Windows both path delimiters are accepted #endif #ifdef _MSC_VER if (s != NULL || b != NULL) #else if (s != NULL) #endif { #ifdef _MSC_VER f = (b > s) ? (b + 1) : (s + 1); #else f = s + 1; #endif strlcpy(f, yyextra->lex_buf, sizeof(buffer) - (f - buffer)); include_path = buffer; } else { include_path = yyextra->lex_buf; } } YR_NAMESPACE* ns = (YR_NAMESPACE*) yr_arena_get_ptr( compiler->arena, YR_NAMESPACES_TABLE, compiler->current_namespace_idx * sizeof(struct YR_NAMESPACE)); included_rules = compiler->include_callback( include_path, current_file_name, ns->name, compiler->incl_clbk_user_data); if (included_rules != NULL) { int error_code = _yr_compiler_push_file_name(compiler, include_path); if (error_code != ERROR_SUCCESS) { if (error_code == ERROR_INCLUDES_CIRCULAR_REFERENCE) { yyerror(yyscanner, compiler, "includes circular reference"); } else if (error_code == ERROR_INCLUDE_DEPTH_EXCEEDED) { yyerror(yyscanner, compiler, "includes depth exceeded"); } if (compiler->include_free != NULL) { compiler->include_free(included_rules, compiler->incl_clbk_user_data); } yyterminate(); } // Workaround for flex issue: https://github.com/westes/flex/issues/58 yypush_buffer_state(YY_CURRENT_BUFFER, yyscanner); yy_scan_string(included_rules, yyscanner); yyset_lineno(1, yyscanner); if (compiler->include_free != NULL) { compiler->include_free(included_rules, compiler->incl_clbk_user_data); } } else { char* err_msg_fmt; char err_msg[512]; if (compiler->include_callback == _yr_compiler_default_include_callback) { err_msg_fmt = "can't open include file: %s"; } else { err_msg_fmt = "callback failed to provide include resource: %s"; } snprintf( err_msg, sizeof(err_msg), err_msg_fmt, yyextra->lex_buf); yyerror(yyscanner, compiler, err_msg); } } else // not allowing includes { yyerror(yyscanner, compiler, "includes are disabled"); } BEGIN(INITIAL); } YY_BREAK case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(str): case YY_STATE_EOF(regexp): case YY_STATE_EOF(include): case YY_STATE_EOF(comment): #line 364 "libyara/lexer.l" { yypop_buffer_state(yyscanner); if (!YY_CURRENT_BUFFER) yyterminate(); return _END_OF_INCLUDED_FILE_; } YY_BREAK case 55: YY_RULE_SETUP #line 375 "libyara/lexer.l" { yylval->c_string = yr_strdup(yytext); if (yylval->c_string == NULL) error(ERROR_INSUFFICIENT_MEMORY); return _STRING_IDENTIFIER_WITH_WILDCARD_; } YY_BREAK case 56: YY_RULE_SETUP #line 386 "libyara/lexer.l" { yylval->c_string = yr_strdup(yytext); if (yylval->c_string == NULL) error(ERROR_INSUFFICIENT_MEMORY); return _STRING_IDENTIFIER_; } YY_BREAK case 57: YY_RULE_SETUP #line 397 "libyara/lexer.l" { yylval->c_string = yr_strdup(yytext); if (yylval->c_string == NULL) { error(ERROR_INSUFFICIENT_MEMORY); } else { yylval->c_string[0] = '$'; /* replace # by $*/ } return _STRING_COUNT_; } YY_BREAK case 58: YY_RULE_SETUP #line 414 "libyara/lexer.l" { yylval->c_string = yr_strdup(yytext); if (yylval->c_string == NULL) { error(ERROR_INSUFFICIENT_MEMORY); } else { yylval->c_string[0] = '$'; /* replace @ by $*/ } return _STRING_OFFSET_; } YY_BREAK case 59: YY_RULE_SETUP #line 431 "libyara/lexer.l" { yylval->c_string = yr_strdup(yytext); if (yylval->c_string == NULL) { error(ERROR_INSUFFICIENT_MEMORY); } else { yylval->c_string[0] = '$'; /* replace ! by $*/ } return _STRING_LENGTH_; } YY_BREAK case 60: YY_RULE_SETUP #line 448 "libyara/lexer.l" { char* text = yytext; if (*text == 'u') { yylval->integer = 3; text++; } else { yylval->integer = 0; } if (strstr(text, "int8") == text) { yylval->integer += 0; text += 4; } else if (strstr(text, "int16") == text) { yylval->integer += 1; text += 5; } else if (strstr(text, "int32") == text) { yylval->integer += 2; text += 5; } if (strcmp(text, "be") == 0) { yylval->integer += 6; } return _INTEGER_FUNCTION_; } YY_BREAK case 61: YY_RULE_SETUP #line 487 "libyara/lexer.l" { if (strlen(yytext) > 128) syntax_error("identifier too long"); yylval->c_string = yr_strdup(yytext); if (yylval->c_string == NULL) error(ERROR_INSUFFICIENT_MEMORY); return _IDENTIFIER_; } YY_BREAK case 62: YY_RULE_SETUP #line 501 "libyara/lexer.l" { char *endptr; errno = 0; yylval->integer = strtoll(yytext, &endptr, 10); if (yylval->integer == LLONG_MAX && errno == ERANGE) { yr_compiler_set_error_extra_info(compiler, yytext); error(ERROR_INTEGER_OVERFLOW); } else if (strstr(yytext, "KB") != NULL) { if (yylval->integer > LLONG_MAX / 1024) { yr_compiler_set_error_extra_info(compiler, yytext); error(ERROR_INTEGER_OVERFLOW); } else { yylval->integer *= 1024; } } else if (strstr(yytext, "MB") != NULL) { if (yylval->integer > LLONG_MAX / 1048576) { yr_compiler_set_error_extra_info(compiler, yytext); error(ERROR_INTEGER_OVERFLOW); } else { yylval->integer *= 1048576; } } return _NUMBER_; } YY_BREAK case 63: YY_RULE_SETUP #line 541 "libyara/lexer.l" { yylval->double_ = atof(yytext); return _DOUBLE_; } YY_BREAK case 64: YY_RULE_SETUP #line 546 "libyara/lexer.l" { char *endptr; errno = 0; yylval->integer = strtoll(yytext, &endptr, 16); if (yylval->integer == LLONG_MAX && errno == ERANGE) { yr_compiler_set_error_extra_info(compiler, yytext); error(ERROR_INTEGER_OVERFLOW); } return _NUMBER_; } YY_BREAK case 65: YY_RULE_SETUP #line 562 "libyara/lexer.l" { char *endptr; errno = 0; yylval->integer = strtoll(yytext + 2, &endptr, 8); if (yylval->integer == LLONG_MAX && errno == ERANGE) { yr_compiler_set_error_extra_info(compiler, yytext); error(ERROR_INTEGER_OVERFLOW); } return _NUMBER_; } YY_BREAK case 66: YY_RULE_SETUP #line 579 "libyara/lexer.l" { /* saw closing quote - all done */ alloc_sized_string(s, yyextra->lex_buf_len); *yyextra->lex_buf_ptr = '\0'; memcpy(s->c_string, yyextra->lex_buf, yyextra->lex_buf_len + 1); yylval->sized_string = s; BEGIN(INITIAL); return _TEXT_STRING_; } YY_BREAK case 67: YY_RULE_SETUP #line 594 "libyara/lexer.l" { lex_check_space_ok("\t", yyextra->lex_buf_len, YR_LEX_BUF_SIZE); *yyextra->lex_buf_ptr++ = '\t'; yyextra->lex_buf_len++; } YY_BREAK case 68: YY_RULE_SETUP #line 602 "libyara/lexer.l" { lex_check_space_ok("\r", yyextra->lex_buf_len, YR_LEX_BUF_SIZE); *yyextra->lex_buf_ptr++ = '\r'; yyextra->lex_buf_len++; } YY_BREAK case 69: YY_RULE_SETUP #line 610 "libyara/lexer.l" { lex_check_space_ok("\n", yyextra->lex_buf_len, YR_LEX_BUF_SIZE); *yyextra->lex_buf_ptr++ = '\n'; yyextra->lex_buf_len++; } YY_BREAK case 70: YY_RULE_SETUP #line 618 "libyara/lexer.l" { lex_check_space_ok("\"", yyextra->lex_buf_len, YR_LEX_BUF_SIZE); *yyextra->lex_buf_ptr++ = '\"'; yyextra->lex_buf_len++; } YY_BREAK case 71: YY_RULE_SETUP #line 626 "libyara/lexer.l" { lex_check_space_ok("\\", yyextra->lex_buf_len, YR_LEX_BUF_SIZE); *yyextra->lex_buf_ptr++ = '\\'; yyextra->lex_buf_len++; } YY_BREAK case 72: YY_RULE_SETUP #line 634 "libyara/lexer.l" { int result; sscanf(yytext + 2, "%x", &result); lex_check_space_ok("X", yyextra->lex_buf_len, YR_LEX_BUF_SIZE); *yyextra->lex_buf_ptr++ = result; yyextra->lex_buf_len++; } YY_BREAK case 73: YY_RULE_SETUP #line 645 "libyara/lexer.l" { yytext_to_buffer; } YY_BREAK case 74: /* rule 74 can match eol */ YY_RULE_SETUP #line 648 "libyara/lexer.l" { syntax_error("unterminated string"); } YY_BREAK case 75: /* rule 75 can match eol */ YY_RULE_SETUP #line 653 "libyara/lexer.l" { syntax_error("illegal escape sequence"); } YY_BREAK case 76: YY_RULE_SETUP #line 658 "libyara/lexer.l" { if (yyextra->lex_buf_len > 0) { alloc_sized_string(s, yyextra->lex_buf_len); if (yytext[1] == 'i') s->flags |= SIZED_STRING_FLAGS_NO_CASE; if (yytext[1] == 's' || yytext[2] == 's') s->flags |= SIZED_STRING_FLAGS_DOT_ALL; *yyextra->lex_buf_ptr = '\0'; strlcpy(s->c_string, yyextra->lex_buf, s->length + 1); yylval->sized_string = s; } else { syntax_error("empty regular expression"); } BEGIN(INITIAL); return _REGEXP_; } YY_BREAK case 77: YY_RULE_SETUP #line 685 "libyara/lexer.l" { lex_check_space_ok("/", yyextra->lex_buf_len, YR_LEX_BUF_SIZE); *yyextra->lex_buf_ptr++ = '/'; yyextra->lex_buf_len++ ; } YY_BREAK case 78: YY_RULE_SETUP #line 693 "libyara/lexer.l" { lex_check_space_ok("\\.", yyextra->lex_buf_len, YR_LEX_BUF_SIZE); if (yytext[1] == 0) syntax_error("malformed regular expression"); *yyextra->lex_buf_ptr++ = yytext[0]; *yyextra->lex_buf_ptr++ = yytext[1]; yyextra->lex_buf_len += 2; } YY_BREAK case 79: YY_RULE_SETUP #line 706 "libyara/lexer.l" { yytext_to_buffer; } YY_BREAK case 80: /* rule 80 can match eol */ YY_RULE_SETUP #line 709 "libyara/lexer.l" { syntax_error("unterminated regular expression"); } YY_BREAK case 81: YY_RULE_SETUP #line 714 "libyara/lexer.l" { yylval->sized_string = NULL; yyextra->lex_buf_ptr = yyextra->lex_buf; yyextra->lex_buf_len = 0; BEGIN(str); } YY_BREAK case 82: YY_RULE_SETUP #line 723 "libyara/lexer.l" { yylval->sized_string = NULL; yyextra->lex_buf_ptr = yyextra->lex_buf; yyextra->lex_buf_len = 0; BEGIN(regexp); } YY_BREAK case 83: /* rule 83 can match eol */ YY_RULE_SETUP #line 732 "libyara/lexer.l" { // Match hex-digits with whitespace or comments. The latter are stripped // out by hex_lexer.l // TODO(vmalvarez): Integrate the hex string lexer and parser into this one, // by having a single lexer/parser instead of two different ones we can avoid // complex regular expressions like the one above, which is actually trying to // do some parsing in the lexer. alloc_sized_string(s, strlen(yytext)); strlcpy(s->c_string, yytext, s->length + 1); yylval->sized_string = s; return _HEX_STRING_; } YY_BREAK case 84: /* rule 84 can match eol */ YY_RULE_SETUP #line 749 "libyara/lexer.l" /* skip whitespace */ YY_BREAK case 85: YY_RULE_SETUP #line 751 "libyara/lexer.l" { if (yytext[0] >= 32 && yytext[0] < 127) { return yytext[0]; } else { syntax_error("non-ascii character"); } } YY_BREAK case 86: YY_RULE_SETUP #line 763 "libyara/lexer.l" ECHO; YY_BREAK #line 2267 "libyara/lexer.c" case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = yyg->yy_hold_char; YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) { /* This was really a NUL. */ yy_state_type yy_next_state; yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( yyscanner ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++yyg->yy_c_buf_p; yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; goto yy_find_action; } } else switch ( yy_get_next_buffer( yyscanner ) ) { case EOB_ACT_END_OF_FILE: { yyg->yy_did_buffer_switch_on_eof = 0; if ( yywrap( yyscanner ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( yyscanner ); yy_cp = yyg->yy_c_buf_p; yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: yyg->yy_c_buf_p = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; yy_current_state = yy_get_previous_state( yyscanner ); yy_cp = yyg->yy_c_buf_p; yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of user's declarations */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; char *source = yyg->yytext_ptr; int number_to_move, i; int ret_val; if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; int yy_c_buf_p_offset = (int) (yyg->yy_c_buf_p - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc( (void *) b->yy_ch_buf, (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = NULL; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), yyg->yy_n_chars, num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } if ( yyg->yy_n_chars == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart( yyin , yyscanner); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); /* "- 2" to take care of EOB's */ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); } yyg->yy_n_chars += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (yyscan_t yyscanner) { yy_state_type yy_current_state; char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_current_state = yyg->yy_start; for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) { YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 295 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) { int yy_is_jam; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ char *yy_cp = yyg->yy_c_buf_p; YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 295 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; yy_is_jam = (yy_current_state == 294); (void)yyg; return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (yyscan_t yyscanner) #else static int input (yyscan_t yyscanner) #endif { int c; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; *yyg->yy_c_buf_p = yyg->yy_hold_char; if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) /* This was really a NUL. */ *yyg->yy_c_buf_p = '\0'; else { /* need more input */ int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); ++yyg->yy_c_buf_p; switch ( yy_get_next_buffer( yyscanner ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart( yyin , yyscanner); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( yyscanner ) ) return 0; if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(yyscanner); #else return input(yyscanner); #endif } case EOB_ACT_CONTINUE_SCAN: yyg->yy_c_buf_p = yyg->yytext_ptr + offset; break; } } } c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ yyg->yy_hold_char = *++yyg->yy_c_buf_p; if ( c == '\n' ) do{ yylineno++; yycolumn=0; }while(0) ; return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * @param yyscanner The scanner object. * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (yyscanner); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); } yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); yy_load_buffer_state( yyscanner ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * @param yyscanner The scanner object. */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (yyscanner); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *yyg->yy_c_buf_p = yyg->yy_hold_char; YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( yyscanner ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ yyg->yy_did_buffer_switch_on_eof = 1; } static void yy_load_buffer_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; yyg->yy_hold_char = *yyg->yy_c_buf_p; } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * @param yyscanner The scanner object. * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer( b, file , yyscanner); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * @param yyscanner The scanner object. */ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree( (void *) b->yy_ch_buf , yyscanner ); yyfree( (void *) b , yyscanner ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) { int oerrno = errno; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_flush_buffer( b , yyscanner); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * @param yyscanner The scanner object. */ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( yyscanner ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * @param yyscanner The scanner object. */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (new_buffer == NULL) return; yyensure_buffer_stack(yyscanner); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *yyg->yy_c_buf_p = yyg->yy_hold_char; YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) yyg->yy_buffer_stack_top++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( yyscanner ); yyg->yy_did_buffer_switch_on_eof = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * @param yyscanner The scanner object. */ void yypop_buffer_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); YY_CURRENT_BUFFER_LVALUE = NULL; if (yyg->yy_buffer_stack_top > 0) --yyg->yy_buffer_stack_top; if (YY_CURRENT_BUFFER) { yy_load_buffer_state( yyscanner ); yyg->yy_did_buffer_switch_on_eof = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (yyscan_t yyscanner) { yy_size_t num_to_alloc; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (!yyg->yy_buffer_stack) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); if ( ! yyg->yy_buffer_stack ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); yyg->yy_buffer_stack_max = num_to_alloc; yyg->yy_buffer_stack_top = 0; return; } if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ /* Increase the buffer to prepare for a possible push. */ yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = yyg->yy_buffer_stack_max + grow_size; yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc (yyg->yy_buffer_stack, num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); if ( ! yyg->yy_buffer_stack ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); /* zero only the new slots.*/ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); yyg->yy_buffer_stack_max = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return NULL; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = NULL; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer( b , yyscanner ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * @param yyscanner The scanner object. * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) { return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param yybytes the byte buffer to scan * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = (yy_size_t) (_yybytes_len + 2); buf = (char *) yyalloc( n , yyscanner ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer( buf, n , yyscanner); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = yyg->yy_hold_char; \ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ yyg->yy_hold_char = *yyg->yy_c_buf_p; \ *yyg->yy_c_buf_p = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the user-defined data for this scanner. * @param yyscanner The scanner object. */ YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyextra; } /** Get the current line number. * @param yyscanner The scanner object. */ int yyget_lineno (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (! YY_CURRENT_BUFFER) return 0; return yylineno; } /** Get the current column number. * @param yyscanner The scanner object. */ int yyget_column (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (! YY_CURRENT_BUFFER) return 0; return yycolumn; } /** Get the input stream. * @param yyscanner The scanner object. */ FILE *yyget_in (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyin; } /** Get the output stream. * @param yyscanner The scanner object. */ FILE *yyget_out (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyout; } /** Get the length of the current token. * @param yyscanner The scanner object. */ int yyget_leng (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyleng; } /** Get the current token. * @param yyscanner The scanner object. */ char *yyget_text (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yytext; } /** Set the user-defined data. This data is never touched by the scanner. * @param user_defined The data to be associated with this scanner. * @param yyscanner The scanner object. */ void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyextra = user_defined ; } /** Set the current line number. * @param _line_number line number * @param yyscanner The scanner object. */ void yyset_lineno (int _line_number , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* lineno is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); yylineno = _line_number; } /** Set the current column. * @param _column_no column number * @param yyscanner The scanner object. */ void yyset_column (int _column_no , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* column is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) YY_FATAL_ERROR( "yyset_column called with no buffer" ); yycolumn = _column_no; } /** Set the input stream. This does not discard the current * input buffer. * @param _in_str A readable stream. * @param yyscanner The scanner object. * @see yy_switch_to_buffer */ void yyset_in (FILE * _in_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyin = _in_str ; } void yyset_out (FILE * _out_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyout = _out_str ; } int yyget_debug (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yy_flex_debug; } void yyset_debug (int _bdebug , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_flex_debug = _bdebug ; } /* Accessor methods for yylval and yylloc */ YYSTYPE * yyget_lval (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yylval; } void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yylval = yylval_param; } /* User-visible API */ /* yylex_init is special because it creates the scanner itself, so it is * the ONLY reentrant function that doesn't take the scanner as the last argument. * That's why we explicitly handle the declaration, instead of using our macros. */ int yylex_init(yyscan_t* ptr_yy_globals) { if (ptr_yy_globals == NULL){ errno = EINVAL; return 1; } *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); if (*ptr_yy_globals == NULL){ errno = ENOMEM; return 1; } /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); return yy_init_globals ( *ptr_yy_globals ); } /* yylex_init_extra has the same functionality as yylex_init, but follows the * convention of taking the scanner as the last argument. Note however, that * this is a *pointer* to a scanner, as it will be allocated by this call (and * is the reason, too, why this function also must handle its own declaration). * The user defined value in the first argument will be available to yyalloc in * the yyextra field. */ int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) { struct yyguts_t dummy_yyguts; yyset_extra (yy_user_defined, &dummy_yyguts); if (ptr_yy_globals == NULL){ errno = EINVAL; return 1; } *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); if (*ptr_yy_globals == NULL){ errno = ENOMEM; return 1; } /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); yyset_extra (yy_user_defined, *ptr_yy_globals); return yy_init_globals ( *ptr_yy_globals ); } static int yy_init_globals (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ yyg->yy_buffer_stack = NULL; yyg->yy_buffer_stack_top = 0; yyg->yy_buffer_stack_max = 0; yyg->yy_c_buf_p = NULL; yyg->yy_init = 0; yyg->yy_start = 0; yyg->yy_start_stack_ptr = 0; yyg->yy_start_stack_depth = 0; yyg->yy_start_stack = NULL; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = NULL; yyout = NULL; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(yyscanner); } /* Destroy the stack itself. */ yyfree(yyg->yy_buffer_stack , yyscanner); yyg->yy_buffer_stack = NULL; /* Destroy the start condition stack. */ yyfree( yyg->yy_start_stack , yyscanner ); yyg->yy_start_stack = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( yyscanner); /* Destroy the main struct (reentrant only). */ yyfree ( yyscanner , yyscanner ); yyscanner = NULL; return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (const char * s , yyscan_t yyscanner) { int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; return malloc(size); } void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return realloc(ptr, size); } void yyfree (void * ptr , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" #line 763 "libyara/lexer.l" void yywarning( yyscan_t yyscanner, const char *message_fmt, ...) { YR_COMPILER* compiler = yyget_extra(yyscanner); char* file_name; char message[512]; va_list message_args; if (compiler->callback == NULL) return; va_start(message_args, message_fmt); if (compiler->file_name_stack_ptr > 0) file_name = compiler->file_name_stack[compiler->file_name_stack_ptr - 1]; else file_name = NULL; vsnprintf(message, sizeof(message), message_fmt, message_args); YR_RULE* current_rule = NULL; if (compiler->current_rule_idx != UINT32_MAX) current_rule = yr_arena_get_ptr( compiler->arena, YR_RULES_TABLE, compiler->current_rule_idx * sizeof(YR_RULE)); compiler->callback( YARA_ERROR_LEVEL_WARNING, file_name, compiler->current_line ? compiler->current_line : yyget_lineno(yyscanner), current_rule, message, compiler->user_data); va_end(message_args); } void yyfatal( yyscan_t yyscanner, const char *error_message) { YR_COMPILER* compiler = yyget_extra(yyscanner); yyerror(yyscanner, compiler, error_message); longjmp(compiler->error_recovery, 1); } void yyerror( yyscan_t yyscanner, YR_COMPILER* compiler, const char *error_message) { char message[512] = {'\0'}; char* file_name = NULL; compiler->errors++; if (compiler->current_line != 0) compiler->last_error_line = compiler->current_line; else compiler->last_error_line = yyget_lineno(yyscanner); compiler->current_line = 0; if (compiler->file_name_stack_ptr > 0) { file_name = compiler->file_name_stack[compiler->file_name_stack_ptr - 1]; } else { file_name = NULL; } YR_RULE* current_rule = NULL; if (compiler->current_rule_idx != UINT32_MAX) current_rule = yr_arena_get_ptr( compiler->arena, YR_RULES_TABLE, compiler->current_rule_idx * sizeof(YR_RULE)); // if error_message != NULL the error comes from yyparse internal code // else the error comes from my code and the error code is set in // compiler->last_error if (error_message != NULL) { yr_compiler_set_error_extra_info(compiler, error_message); compiler->last_error = ERROR_SYNTAX_ERROR; if (compiler->callback != NULL) { compiler->callback( YARA_ERROR_LEVEL_ERROR, file_name, compiler->last_error_line, current_rule, error_message, compiler->user_data); } } else if (compiler->callback != NULL) { yr_compiler_get_error_message(compiler, message, sizeof(message)); compiler->callback( YARA_ERROR_LEVEL_ERROR, file_name, compiler->last_error_line, current_rule, message, compiler->user_data); } } int yr_lex_parse_rules_bytes( const void* rules_data, size_t rules_size, YR_COMPILER* compiler) { yyscan_t yyscanner; compiler->errors = 0; if (rules_data == NULL) return 0; if (yylex_init(&yyscanner) != 0) { compiler->errors = 1; compiler->last_error = ERROR_INSUFFICIENT_MEMORY; return compiler->errors; } if (setjmp(compiler->error_recovery) != 0) return compiler->errors; #if YYDEBUG yydebug = 1; #endif yyset_extra(compiler, yyscanner); yy_scan_bytes(rules_data, rules_size, yyscanner); yyset_lineno(1, yyscanner); yyparse(yyscanner, compiler); yylex_destroy(yyscanner); return compiler->errors; } int yr_lex_parse_rules_string( const char* rules_string, YR_COMPILER* compiler) { yyscan_t yyscanner; compiler->errors = 0; if (rules_string == NULL) return 0; if (yylex_init(&yyscanner) != 0) { compiler->errors = 1; compiler->last_error = ERROR_INSUFFICIENT_MEMORY; return compiler->errors; } if (setjmp(compiler->error_recovery) != 0) return compiler->errors; #if YYDEBUG yydebug = 1; #endif yyset_extra(compiler, yyscanner); yy_scan_string(rules_string, yyscanner); yyset_lineno(1, yyscanner); yyparse(yyscanner, compiler); yylex_destroy(yyscanner); return compiler->errors; } int yr_lex_parse_rules_file( FILE* rules_file, YR_COMPILER* compiler) { yyscan_t yyscanner; compiler->errors = 0; if (yylex_init(&yyscanner) != 0) { compiler->errors = 1; compiler->last_error = ERROR_INSUFFICIENT_MEMORY; return compiler->errors; } if (setjmp(compiler->error_recovery) != 0) return compiler->errors; #if YYDEBUG yydebug = 1; #endif yyset_in(rules_file, yyscanner); yyset_extra(compiler, yyscanner); yyparse(yyscanner, compiler); yylex_destroy(yyscanner); return compiler->errors; } int yr_lex_parse_rules_fd( YR_FILE_DESCRIPTOR rules_fd, YR_COMPILER* compiler) { yyscan_t yyscanner; size_t file_size; void* buffer; #if defined(_WIN32) || defined(__CYGWIN__) DWORD bytes_read; #endif compiler->errors = 0; if (setjmp(compiler->error_recovery) != 0) return compiler->errors; #if defined(_WIN32) || defined(__CYGWIN__) file_size = (size_t) GetFileSize(rules_fd, NULL); #else struct stat fs; if (fstat(rules_fd, &fs) != 0) { compiler->errors = 1; compiler->last_error = ERROR_COULD_NOT_READ_FILE; return compiler->errors; } file_size = (size_t) fs.st_size; #endif buffer = yr_malloc(file_size); if (buffer == NULL) { compiler->errors = 1; compiler->last_error = ERROR_INSUFFICIENT_MEMORY; return compiler->errors; } #if defined(_WIN32) || defined(__CYGWIN__) if (!ReadFile(rules_fd, buffer, file_size, &bytes_read, NULL)) #else if (read(rules_fd, buffer, file_size) != file_size) #endif { yr_free(buffer); compiler->errors = 1; compiler->last_error = ERROR_COULD_NOT_READ_FILE; return compiler->errors; } if (yylex_init(&yyscanner) != 0) { yr_free(buffer); compiler->errors = 1; compiler->last_error = ERROR_INSUFFICIENT_MEMORY; return compiler->errors; } #if YYDEBUG yydebug = 1; #endif yyset_extra(compiler, yyscanner); yy_scan_bytes((const char*) buffer, (int) file_size, yyscanner); yyset_lineno(1, yyscanner); yyparse(yyscanner, compiler); yylex_destroy(yyscanner); yr_free(buffer); return compiler->errors; } yara-4.5.3/libyara/lexer.l000066400000000000000000000556731501365277300154270ustar00rootroot00000000000000/* Copyright (c) 2007-2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Lexical analyzer for YARA */ %{ /* Disable warnings for unused functions in this file. As we redefine YY_FATAL_ERROR macro to use our own function yara_yyfatal, the yy_fatal_error function generated by Flex is not actually used, causing a compiler warning. Flex doesn't offer any options to remove the yy_fatal_error function. When they include something like %option noyy_fatal_error as they do with noyywrap then we can remove this pragma. */ #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wunused-function" #endif #include #include #include #include #include #include #if defined(_WIN32) || defined(__CYGWIN__) #include #else #include #include #endif #if defined(_WIN32) #define strtoll _strtoi64 #endif #include #include #include #include #include #include #include #include "grammar.h" #define error(error_code) \ { \ compiler->last_error = error_code; \ yyerror(yyscanner, compiler, NULL); \ yyterminate(); \ } #define syntax_error(error_msg) \ { \ yr_compiler_set_error_extra_info(compiler, error_msg); \ error(ERROR_SYNTAX_ERROR); \ } #define lex_check_space_ok(data, current_size, max_length) \ if (strlen(data) + current_size >= max_length - 1) \ { \ yyerror(yyscanner, compiler, "out of space in lex_buf"); \ yyterminate(); \ } #define yytext_to_buffer \ { \ char *yptr = yytext; \ lex_check_space_ok(yptr, yyextra->lex_buf_len, YR_LEX_BUF_SIZE); \ while(*yptr) \ { \ *yyextra->lex_buf_ptr++ = *yptr++; \ yyextra->lex_buf_len++; \ } \ } #define alloc_sized_string(str, str_len) \ SIZED_STRING* str = (SIZED_STRING*) yr_malloc( \ str_len + sizeof(SIZED_STRING)); \ if (str == NULL) \ { \ yyerror(yyscanner, compiler, "not enough memory"); \ yyterminate(); \ } \ else \ { \ str->length = (uint32_t) (str_len); \ str->flags = 0; \ } \ #ifdef _WIN32 #define snprintf _snprintf #endif static bool is_absolute_path( char* path) { if (path == NULL) return false; #if defined(_WIN32) || defined(__CYGWIN__) return strlen(path) > 2 && path[1] == ':' && (path[2] == '/' || path[2] == '\\'); #else return strlen(path) > 0 && path[0] == '/'; #endif } %} %option reentrant bison-bridge %option noyywrap %option nounistd %option noinput %option nounput %option never-interactive %option yylineno %option prefix="yara_yy" %option outfile="lex.yy.c" %option verbose %option warn %x str %x regexp %x include %x comment digit [0-9] letter [a-zA-Z] hexdigit [a-fA-F0-9] octdigit [0-7] %% ".." { return _DOT_DOT_; } "<" { return _LT_; } ">" { return _GT_; } "<=" { return _LE_; } ">=" { return _GE_; } "==" { return _EQ_; } "!=" { return _NEQ_; } "<<" { return _SHIFT_LEFT_; } ">>" { return _SHIFT_RIGHT_; } "private" { return _PRIVATE_; } "global" { return _GLOBAL_; } "rule" { return _RULE_; } "meta" { return _META_; } "strings" { return _STRINGS_; } "ascii" { return _ASCII_; } "wide" { return _WIDE_; } "xor" { return _XOR_; } "base64" { return _BASE64_; } "base64wide" { return _BASE64_WIDE_; } "fullword" { return _FULLWORD_; } "nocase" { return _NOCASE_; } "condition" { return _CONDITION_; } "true" { return _TRUE_; } "false" { return _FALSE_; } "not" { return _NOT_; } "and" { return _AND_; } "or" { return _OR_; } "at" { return _AT_; } "in" { return _IN_; } "of" { return _OF_; } "them" { return _THEM_; } "for" { return _FOR_; } "all" { return _ALL_; } "any" { return _ANY_; } "none" { return _NONE_; } "entrypoint" { return _ENTRYPOINT_; } "filesize" { return _FILESIZE_; } "matches" { return _MATCHES_; } "contains" { return _CONTAINS_; } "startswith" { return _STARTSWITH_; } "endswith" { return _ENDSWITH_; } "icontains" { return _ICONTAINS_; } "istartswith" { return _ISTARTSWITH_; } "iendswith" { return _IENDSWITH_; } "iequals" { return _IEQUALS_; } "import" { return _IMPORT_; } "defined" { return _DEFINED_; } "/*" { BEGIN(comment); } "*/" { BEGIN(INITIAL); } (.|\n) { /* skip comments */ } "//"[^\n]* { /* skip single-line comments */ } include[ \t]+\" { yyextra->lex_buf_ptr = yyextra->lex_buf; yyextra->lex_buf_len = 0; BEGIN(include); } [^\"]+ { yytext_to_buffer; } \" { if (compiler->include_callback != NULL) { #ifdef _MSC_VER char* b = NULL; #endif char* s = NULL; char* f; char buffer[1024]; const char* included_rules; char* current_file_name; char* include_path; *yyextra->lex_buf_ptr = '\0'; // null-terminate included file path current_file_name = yr_compiler_get_current_file_name(compiler); if (current_file_name == NULL || compiler->include_callback != _yr_compiler_default_include_callback || is_absolute_path(yyextra->lex_buf)) { include_path = yyextra->lex_buf; } else { strlcpy(buffer, current_file_name, sizeof(buffer)); s = strrchr(buffer, '/'); #ifdef _MSC_VER b = strrchr(buffer, '\\'); // in Windows both path delimiters are accepted #endif #ifdef _MSC_VER if (s != NULL || b != NULL) #else if (s != NULL) #endif { #ifdef _MSC_VER f = (b > s) ? (b + 1) : (s + 1); #else f = s + 1; #endif strlcpy(f, yyextra->lex_buf, sizeof(buffer) - (f - buffer)); include_path = buffer; } else { include_path = yyextra->lex_buf; } } YR_NAMESPACE* ns = (YR_NAMESPACE*) yr_arena_get_ptr( compiler->arena, YR_NAMESPACES_TABLE, compiler->current_namespace_idx * sizeof(struct YR_NAMESPACE)); included_rules = compiler->include_callback( include_path, current_file_name, ns->name, compiler->incl_clbk_user_data); if (included_rules != NULL) { int error_code = _yr_compiler_push_file_name(compiler, include_path); if (error_code != ERROR_SUCCESS) { if (error_code == ERROR_INCLUDES_CIRCULAR_REFERENCE) { yyerror(yyscanner, compiler, "includes circular reference"); } else if (error_code == ERROR_INCLUDE_DEPTH_EXCEEDED) { yyerror(yyscanner, compiler, "includes depth exceeded"); } if (compiler->include_free != NULL) { compiler->include_free(included_rules, compiler->incl_clbk_user_data); } yyterminate(); } // Workaround for flex issue: https://github.com/westes/flex/issues/58 yypush_buffer_state(YY_CURRENT_BUFFER, yyscanner); yy_scan_string(included_rules, yyscanner); yyset_lineno(1, yyscanner); if (compiler->include_free != NULL) { compiler->include_free(included_rules, compiler->incl_clbk_user_data); } } else { char* err_msg_fmt; char err_msg[512]; if (compiler->include_callback == _yr_compiler_default_include_callback) { err_msg_fmt = "can't open include file: %s"; } else { err_msg_fmt = "callback failed to provide include resource: %s"; } snprintf( err_msg, sizeof(err_msg), err_msg_fmt, yyextra->lex_buf); yyerror(yyscanner, compiler, err_msg); } } else // not allowing includes { yyerror(yyscanner, compiler, "includes are disabled"); } BEGIN(INITIAL); } <> { yypop_buffer_state(yyscanner); if (!YY_CURRENT_BUFFER) yyterminate(); return _END_OF_INCLUDED_FILE_; } $({letter}|{digit}|_)*"*" { yylval->c_string = yr_strdup(yytext); if (yylval->c_string == NULL) error(ERROR_INSUFFICIENT_MEMORY); return _STRING_IDENTIFIER_WITH_WILDCARD_; } $({letter}|{digit}|_)* { yylval->c_string = yr_strdup(yytext); if (yylval->c_string == NULL) error(ERROR_INSUFFICIENT_MEMORY); return _STRING_IDENTIFIER_; } #({letter}|{digit}|_)* { yylval->c_string = yr_strdup(yytext); if (yylval->c_string == NULL) { error(ERROR_INSUFFICIENT_MEMORY); } else { yylval->c_string[0] = '$'; /* replace # by $*/ } return _STRING_COUNT_; } @({letter}|{digit}|_)* { yylval->c_string = yr_strdup(yytext); if (yylval->c_string == NULL) { error(ERROR_INSUFFICIENT_MEMORY); } else { yylval->c_string[0] = '$'; /* replace @ by $*/ } return _STRING_OFFSET_; } !({letter}|{digit}|_)* { yylval->c_string = yr_strdup(yytext); if (yylval->c_string == NULL) { error(ERROR_INSUFFICIENT_MEMORY); } else { yylval->c_string[0] = '$'; /* replace ! by $*/ } return _STRING_LENGTH_; } u?int(8|16|32)(be)? { char* text = yytext; if (*text == 'u') { yylval->integer = 3; text++; } else { yylval->integer = 0; } if (strstr(text, "int8") == text) { yylval->integer += 0; text += 4; } else if (strstr(text, "int16") == text) { yylval->integer += 1; text += 5; } else if (strstr(text, "int32") == text) { yylval->integer += 2; text += 5; } if (strcmp(text, "be") == 0) { yylval->integer += 6; } return _INTEGER_FUNCTION_; } ({letter}|_)({letter}|{digit}|_)* { if (strlen(yytext) > 128) syntax_error("identifier too long"); yylval->c_string = yr_strdup(yytext); if (yylval->c_string == NULL) error(ERROR_INSUFFICIENT_MEMORY); return _IDENTIFIER_; } {digit}+(MB|KB){0,1} { char *endptr; errno = 0; yylval->integer = strtoll(yytext, &endptr, 10); if (yylval->integer == LLONG_MAX && errno == ERANGE) { yr_compiler_set_error_extra_info(compiler, yytext); error(ERROR_INTEGER_OVERFLOW); } else if (strstr(yytext, "KB") != NULL) { if (yylval->integer > LLONG_MAX / 1024) { yr_compiler_set_error_extra_info(compiler, yytext); error(ERROR_INTEGER_OVERFLOW); } else { yylval->integer *= 1024; } } else if (strstr(yytext, "MB") != NULL) { if (yylval->integer > LLONG_MAX / 1048576) { yr_compiler_set_error_extra_info(compiler, yytext); error(ERROR_INTEGER_OVERFLOW); } else { yylval->integer *= 1048576; } } return _NUMBER_; } {digit}+"."{digit}+ { yylval->double_ = atof(yytext); return _DOUBLE_; } 0x{hexdigit}+ { char *endptr; errno = 0; yylval->integer = strtoll(yytext, &endptr, 16); if (yylval->integer == LLONG_MAX && errno == ERANGE) { yr_compiler_set_error_extra_info(compiler, yytext); error(ERROR_INTEGER_OVERFLOW); } return _NUMBER_; } 0o{octdigit}+ { char *endptr; errno = 0; yylval->integer = strtoll(yytext + 2, &endptr, 8); if (yylval->integer == LLONG_MAX && errno == ERANGE) { yr_compiler_set_error_extra_info(compiler, yytext); error(ERROR_INTEGER_OVERFLOW); } return _NUMBER_; } \" { /* saw closing quote - all done */ alloc_sized_string(s, yyextra->lex_buf_len); *yyextra->lex_buf_ptr = '\0'; memcpy(s->c_string, yyextra->lex_buf, yyextra->lex_buf_len + 1); yylval->sized_string = s; BEGIN(INITIAL); return _TEXT_STRING_; } \\t { lex_check_space_ok("\t", yyextra->lex_buf_len, YR_LEX_BUF_SIZE); *yyextra->lex_buf_ptr++ = '\t'; yyextra->lex_buf_len++; } \\r { lex_check_space_ok("\r", yyextra->lex_buf_len, YR_LEX_BUF_SIZE); *yyextra->lex_buf_ptr++ = '\r'; yyextra->lex_buf_len++; } \\n { lex_check_space_ok("\n", yyextra->lex_buf_len, YR_LEX_BUF_SIZE); *yyextra->lex_buf_ptr++ = '\n'; yyextra->lex_buf_len++; } \\\" { lex_check_space_ok("\"", yyextra->lex_buf_len, YR_LEX_BUF_SIZE); *yyextra->lex_buf_ptr++ = '\"'; yyextra->lex_buf_len++; } \\\\ { lex_check_space_ok("\\", yyextra->lex_buf_len, YR_LEX_BUF_SIZE); *yyextra->lex_buf_ptr++ = '\\'; yyextra->lex_buf_len++; } \\x{hexdigit}{2} { int result; sscanf(yytext + 2, "%x", &result); lex_check_space_ok("X", yyextra->lex_buf_len, YR_LEX_BUF_SIZE); *yyextra->lex_buf_ptr++ = result; yyextra->lex_buf_len++; } [^\\\n\"]+ { yytext_to_buffer; } \n { syntax_error("unterminated string"); } \\(.|\n) { syntax_error("illegal escape sequence"); } \/i?s? { if (yyextra->lex_buf_len > 0) { alloc_sized_string(s, yyextra->lex_buf_len); if (yytext[1] == 'i') s->flags |= SIZED_STRING_FLAGS_NO_CASE; if (yytext[1] == 's' || yytext[2] == 's') s->flags |= SIZED_STRING_FLAGS_DOT_ALL; *yyextra->lex_buf_ptr = '\0'; strlcpy(s->c_string, yyextra->lex_buf, s->length + 1); yylval->sized_string = s; } else { syntax_error("empty regular expression"); } BEGIN(INITIAL); return _REGEXP_; } \\\/ { lex_check_space_ok("/", yyextra->lex_buf_len, YR_LEX_BUF_SIZE); *yyextra->lex_buf_ptr++ = '/'; yyextra->lex_buf_len++ ; } \\. { lex_check_space_ok("\\.", yyextra->lex_buf_len, YR_LEX_BUF_SIZE); if (yytext[1] == 0) syntax_error("malformed regular expression"); *yyextra->lex_buf_ptr++ = yytext[0]; *yyextra->lex_buf_ptr++ = yytext[1]; yyextra->lex_buf_len += 2; } [^/\n\\]+ { yytext_to_buffer; } \n { syntax_error("unterminated regular expression"); } \" { yylval->sized_string = NULL; yyextra->lex_buf_ptr = yyextra->lex_buf; yyextra->lex_buf_len = 0; BEGIN(str); } "/" { yylval->sized_string = NULL; yyextra->lex_buf_ptr = yyextra->lex_buf; yyextra->lex_buf_len = 0; BEGIN(regexp); } \{(({hexdigit}|[ \-|\~\?\[\]\(\)\n\r\t]|\/\*(\/|\**[^*/])*\*+\/)+|\/\/.*\n)+\} { // Match hex-digits with whitespace or comments. The latter are stripped // out by hex_lexer.l // TODO(vmalvarez): Integrate the hex string lexer and parser into this one, // by having a single lexer/parser instead of two different ones we can avoid // complex regular expressions like the one above, which is actually trying to // do some parsing in the lexer. alloc_sized_string(s, strlen(yytext)); strlcpy(s->c_string, yytext, s->length + 1); yylval->sized_string = s; return _HEX_STRING_; } [ \t\r\n] /* skip whitespace */ . { if (yytext[0] >= 32 && yytext[0] < 127) { return yytext[0]; } else { syntax_error("non-ascii character"); } } %% void yywarning( yyscan_t yyscanner, const char *message_fmt, ...) { YR_COMPILER* compiler = yyget_extra(yyscanner); char* file_name; char message[512]; va_list message_args; if (compiler->callback == NULL) return; va_start(message_args, message_fmt); if (compiler->file_name_stack_ptr > 0) file_name = compiler->file_name_stack[compiler->file_name_stack_ptr - 1]; else file_name = NULL; vsnprintf(message, sizeof(message), message_fmt, message_args); YR_RULE* current_rule = NULL; if (compiler->current_rule_idx != UINT32_MAX) current_rule = yr_arena_get_ptr( compiler->arena, YR_RULES_TABLE, compiler->current_rule_idx * sizeof(YR_RULE)); compiler->callback( YARA_ERROR_LEVEL_WARNING, file_name, compiler->current_line ? compiler->current_line : yyget_lineno(yyscanner), current_rule, message, compiler->user_data); va_end(message_args); } void yyfatal( yyscan_t yyscanner, const char *error_message) { YR_COMPILER* compiler = yyget_extra(yyscanner); yyerror(yyscanner, compiler, error_message); longjmp(compiler->error_recovery, 1); } void yyerror( yyscan_t yyscanner, YR_COMPILER* compiler, const char *error_message) { char message[512] = {'\0'}; char* file_name = NULL; compiler->errors++; if (compiler->current_line != 0) compiler->last_error_line = compiler->current_line; else compiler->last_error_line = yyget_lineno(yyscanner); compiler->current_line = 0; if (compiler->file_name_stack_ptr > 0) { file_name = compiler->file_name_stack[compiler->file_name_stack_ptr - 1]; } else { file_name = NULL; } YR_RULE* current_rule = NULL; if (compiler->current_rule_idx != UINT32_MAX) current_rule = yr_arena_get_ptr( compiler->arena, YR_RULES_TABLE, compiler->current_rule_idx * sizeof(YR_RULE)); // if error_message != NULL the error comes from yyparse internal code // else the error comes from my code and the error code is set in // compiler->last_error if (error_message != NULL) { yr_compiler_set_error_extra_info(compiler, error_message); compiler->last_error = ERROR_SYNTAX_ERROR; if (compiler->callback != NULL) { compiler->callback( YARA_ERROR_LEVEL_ERROR, file_name, compiler->last_error_line, current_rule, error_message, compiler->user_data); } } else if (compiler->callback != NULL) { yr_compiler_get_error_message(compiler, message, sizeof(message)); compiler->callback( YARA_ERROR_LEVEL_ERROR, file_name, compiler->last_error_line, current_rule, message, compiler->user_data); } } int yr_lex_parse_rules_bytes( const void* rules_data, size_t rules_size, YR_COMPILER* compiler) { yyscan_t yyscanner; compiler->errors = 0; if (rules_data == NULL) return 0; if (yylex_init(&yyscanner) != 0) { compiler->errors = 1; compiler->last_error = ERROR_INSUFFICIENT_MEMORY; return compiler->errors; } if (setjmp(compiler->error_recovery) != 0) return compiler->errors; #if YYDEBUG yydebug = 1; #endif yyset_extra(compiler, yyscanner); yy_scan_bytes(rules_data, rules_size, yyscanner); yyset_lineno(1, yyscanner); yyparse(yyscanner, compiler); yylex_destroy(yyscanner); return compiler->errors; } int yr_lex_parse_rules_string( const char* rules_string, YR_COMPILER* compiler) { yyscan_t yyscanner; compiler->errors = 0; if (rules_string == NULL) return 0; if (yylex_init(&yyscanner) != 0) { compiler->errors = 1; compiler->last_error = ERROR_INSUFFICIENT_MEMORY; return compiler->errors; } if (setjmp(compiler->error_recovery) != 0) return compiler->errors; #if YYDEBUG yydebug = 1; #endif yyset_extra(compiler, yyscanner); yy_scan_string(rules_string, yyscanner); yyset_lineno(1, yyscanner); yyparse(yyscanner, compiler); yylex_destroy(yyscanner); return compiler->errors; } int yr_lex_parse_rules_file( FILE* rules_file, YR_COMPILER* compiler) { yyscan_t yyscanner; compiler->errors = 0; if (yylex_init(&yyscanner) != 0) { compiler->errors = 1; compiler->last_error = ERROR_INSUFFICIENT_MEMORY; return compiler->errors; } if (setjmp(compiler->error_recovery) != 0) return compiler->errors; #if YYDEBUG yydebug = 1; #endif yyset_in(rules_file, yyscanner); yyset_extra(compiler, yyscanner); yyparse(yyscanner, compiler); yylex_destroy(yyscanner); return compiler->errors; } int yr_lex_parse_rules_fd( YR_FILE_DESCRIPTOR rules_fd, YR_COMPILER* compiler) { yyscan_t yyscanner; size_t file_size; void* buffer; #if defined(_WIN32) || defined(__CYGWIN__) DWORD bytes_read; #endif compiler->errors = 0; if (setjmp(compiler->error_recovery) != 0) return compiler->errors; #if defined(_WIN32) || defined(__CYGWIN__) file_size = (size_t) GetFileSize(rules_fd, NULL); #else struct stat fs; if (fstat(rules_fd, &fs) != 0) { compiler->errors = 1; compiler->last_error = ERROR_COULD_NOT_READ_FILE; return compiler->errors; } file_size = (size_t) fs.st_size; #endif buffer = yr_malloc(file_size); if (buffer == NULL) { compiler->errors = 1; compiler->last_error = ERROR_INSUFFICIENT_MEMORY; return compiler->errors; } #if defined(_WIN32) || defined(__CYGWIN__) if (!ReadFile(rules_fd, buffer, file_size, &bytes_read, NULL)) #else if (read(rules_fd, buffer, file_size) != file_size) #endif { yr_free(buffer); compiler->errors = 1; compiler->last_error = ERROR_COULD_NOT_READ_FILE; return compiler->errors; } if (yylex_init(&yyscanner) != 0) { yr_free(buffer); compiler->errors = 1; compiler->last_error = ERROR_INSUFFICIENT_MEMORY; return compiler->errors; } #if YYDEBUG yydebug = 1; #endif yyset_extra(compiler, yyscanner); yy_scan_bytes((const char*) buffer, (int) file_size, yyscanner); yyset_lineno(1, yyscanner); yyparse(yyscanner, compiler); yylex_destroy(yyscanner); yr_free(buffer); return compiler->errors; } yara-4.5.3/libyara/libyara.c000066400000000000000000000470361501365277300157140ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if defined(JEMALLOC) #include #endif #include #include #include #include #include #include #include #include #include #include "crypto.h" #if defined(_WIN32) || defined(__CYGWIN__) #if !defined(_MSC_VER) || (defined(_MSC_VER) && (_MSC_VER < 1900)) #define snprintf _snprintf #endif #endif YR_THREAD_STORAGE_KEY yr_yyfatal_trampoline_tls; YR_THREAD_STORAGE_KEY yr_trycatch_trampoline_tls; #if !(_WIN32 || __CYGWIN__) #include #include struct sigaction old_sigsegv_exception_handler; struct sigaction old_sigbus_exception_handler; int exception_handler_usecount = 0; pthread_mutex_t exception_handler_mutex = PTHREAD_MUTEX_INITIALIZER; #endif static int init_count = 0; static struct yr_config_var { union { size_t sz; uint32_t ui32; uint64_t ui64; char *str; }; } yr_cfgs[YR_CONFIG_LAST]; // Global variables. See globals.h for their descriptions. uint8_t yr_lowercase[256]; uint8_t yr_altercase[256]; #if 0 == YR_DEBUG_VERBOSITY #else uint64_t yr_debug_verbosity = YR_DEBUG_VERBOSITY; YR_TLS int yr_debug_indent = 0; YR_TLS int yr_debug_stopwatch_unstarted = 1; YR_TLS YR_STOPWATCH yr_debug_stopwatch; const char yr_debug_spaces[] = " " /* 16 spaces * 1 */ " " /* 16 spaces * 2 */ " " /* 16 spaces * 3 */ " " /* 16 spaces * 4 */ " " /* 16 spaces * 5 */ " " /* 16 spaces * 6 */ " " /* 16 spaces * 7 */ " " /* 16 spaces * 8 */; size_t yr_debug_spaces_len = sizeof(yr_debug_spaces); double yr_debug_get_elapsed_seconds(void) { if (yr_debug_stopwatch_unstarted) { yr_debug_stopwatch_unstarted = 0; yr_stopwatch_start(&yr_debug_stopwatch); } uint64_t elapsed_ns = yr_stopwatch_elapsed_ns(&yr_debug_stopwatch); double seconds = (double) elapsed_ns / 1000000000; return seconds; } char *yr_debug_callback_message_as_string(int message) { char *s = "CALLBACK_MSG_?"; switch (message) { // clang-format off case CALLBACK_MSG_RULE_MATCHING : s = "CALLBACK_MSG_RULE_MATCHING" ; break; case CALLBACK_MSG_RULE_NOT_MATCHING: s = "CALLBACK_MSG_RULE_NOT_MATCHING"; break; case CALLBACK_MSG_SCAN_FINISHED : s = "CALLBACK_MSG_SCAN_FINISHED" ; break; case CALLBACK_MSG_IMPORT_MODULE : s = "CALLBACK_MSG_IMPORT_MODULE" ; break; case CALLBACK_MSG_MODULE_IMPORTED : s = "CALLBACK_MSG_MODULE_IMPORTED" ; break; } // clang-format on return s; } char *yr_debug_error_as_string(int error) { char *s = "ERROR_?"; switch (error) { // clang-format off case ERROR_SUCCESS : s = "ERROR_SUCCESS 0" ; break; case ERROR_INSUFFICIENT_MEMORY : s = "ERROR_INSUFFICIENT_MEMORY" ; break; case ERROR_COULD_NOT_ATTACH_TO_PROCESS : s = "ERROR_COULD_NOT_ATTACH_TO_PROCESS" ; break; case ERROR_COULD_NOT_OPEN_FILE : s = "ERROR_COULD_NOT_OPEN_FILE" ; break; case ERROR_COULD_NOT_MAP_FILE : s = "ERROR_COULD_NOT_MAP_FILE" ; break; case ERROR_INVALID_FILE : s = "ERROR_INVALID_FILE" ; break; case ERROR_CORRUPT_FILE : s = "ERROR_CORRUPT_FILE" ; break; case ERROR_UNSUPPORTED_FILE_VERSION : s = "ERROR_UNSUPPORTED_FILE_VERSION" ; break; case ERROR_INVALID_REGULAR_EXPRESSION : s = "ERROR_INVALID_REGULAR_EXPRESSION" ; break; case ERROR_INVALID_HEX_STRING : s = "ERROR_INVALID_HEX_STRING" ; break; case ERROR_SYNTAX_ERROR : s = "ERROR_SYNTAX_ERROR" ; break; case ERROR_LOOP_NESTING_LIMIT_EXCEEDED : s = "ERROR_LOOP_NESTING_LIMIT_EXCEEDED" ; break; case ERROR_DUPLICATED_LOOP_IDENTIFIER : s = "ERROR_DUPLICATED_LOOP_IDENTIFIER" ; break; case ERROR_DUPLICATED_IDENTIFIER : s = "ERROR_DUPLICATED_IDENTIFIER" ; break; case ERROR_DUPLICATED_TAG_IDENTIFIER : s = "ERROR_DUPLICATED_TAG_IDENTIFIER" ; break; case ERROR_DUPLICATED_META_IDENTIFIER : s = "ERROR_DUPLICATED_META_IDENTIFIER" ; break; case ERROR_DUPLICATED_STRING_IDENTIFIER : s = "ERROR_DUPLICATED_STRING_IDENTIFIER" ; break; case ERROR_UNREFERENCED_STRING : s = "ERROR_UNREFERENCED_STRING" ; break; case ERROR_UNDEFINED_STRING : s = "ERROR_UNDEFINED_STRING" ; break; case ERROR_UNDEFINED_IDENTIFIER : s = "ERROR_UNDEFINED_IDENTIFIER" ; break; case ERROR_MISPLACED_ANONYMOUS_STRING : s = "ERROR_MISPLACED_ANONYMOUS_STRING" ; break; case ERROR_INCLUDES_CIRCULAR_REFERENCE : s = "ERROR_INCLUDES_CIRCULAR_REFERENCE" ; break; case ERROR_INCLUDE_DEPTH_EXCEEDED : s = "ERROR_INCLUDE_DEPTH_EXCEEDED" ; break; case ERROR_WRONG_TYPE : s = "ERROR_WRONG_TYPE" ; break; case ERROR_EXEC_STACK_OVERFLOW : s = "ERROR_EXEC_STACK_OVERFLOW" ; break; case ERROR_SCAN_TIMEOUT : s = "ERROR_SCAN_TIMEOUT" ; break; case ERROR_CALLBACK_ERROR : s = "ERROR_CALLBACK_ERROR" ; break; case ERROR_INVALID_ARGUMENT : s = "ERROR_INVALID_ARGUMENT" ; break; case ERROR_TOO_MANY_MATCHES : s = "ERROR_TOO_MANY_MATCHES" ; break; case ERROR_INTERNAL_FATAL_ERROR : s = "ERROR_INTERNAL_FATAL_ERROR" ; break; case ERROR_NESTED_FOR_OF_LOOP : s = "ERROR_NESTED_FOR_OF_LOOP" ; break; case ERROR_INVALID_FIELD_NAME : s = "ERROR_INVALID_FIELD_NAME" ; break; case ERROR_UNKNOWN_MODULE : s = "ERROR_UNKNOWN_MODULE" ; break; case ERROR_NOT_A_STRUCTURE : s = "ERROR_NOT_A_STRUCTURE" ; break; case ERROR_NOT_INDEXABLE : s = "ERROR_NOT_INDEXABLE" ; break; case ERROR_NOT_A_FUNCTION : s = "ERROR_NOT_A_FUNCTION" ; break; case ERROR_INVALID_FORMAT : s = "ERROR_INVALID_FORMAT" ; break; case ERROR_TOO_MANY_ARGUMENTS : s = "ERROR_TOO_MANY_ARGUMENTS" ; break; case ERROR_WRONG_ARGUMENTS : s = "ERROR_WRONG_ARGUMENTS" ; break; case ERROR_WRONG_RETURN_TYPE : s = "ERROR_WRONG_RETURN_TYPE" ; break; case ERROR_DUPLICATED_STRUCTURE_MEMBER : s = "ERROR_DUPLICATED_STRUCTURE_MEMBER" ; break; case ERROR_EMPTY_STRING : s = "ERROR_EMPTY_STRING" ; break; case ERROR_DIVISION_BY_ZERO : s = "ERROR_DIVISION_BY_ZERO" ; break; case ERROR_REGULAR_EXPRESSION_TOO_LARGE : s = "ERROR_REGULAR_EXPRESSION_TOO_LARGE" ; break; case ERROR_TOO_MANY_RE_FIBERS : s = "ERROR_TOO_MANY_RE_FIBERS" ; break; case ERROR_COULD_NOT_READ_PROCESS_MEMORY : s = "ERROR_COULD_NOT_READ_PROCESS_MEMORY" ; break; case ERROR_INVALID_EXTERNAL_VARIABLE_TYPE: s = "ERROR_INVALID_EXTERNAL_VARIABLE_TYPE"; break; case ERROR_REGULAR_EXPRESSION_TOO_COMPLEX: s = "ERROR_REGULAR_EXPRESSION_TOO_COMPLEX"; break; case ERROR_INVALID_MODULE_NAME : s = "ERROR_INVALID_MODULE_NAME" ; break; case ERROR_TOO_MANY_STRINGS : s = "ERROR_TOO_MANY_STRINGS" ; break; case ERROR_INTEGER_OVERFLOW : s = "ERROR_INTEGER_OVERFLOW" ; break; case ERROR_CALLBACK_REQUIRED : s = "ERROR_CALLBACK_REQUIRED" ; break; case ERROR_INVALID_OPERAND : s = "ERROR_INVALID_OPERAND" ; break; case ERROR_COULD_NOT_READ_FILE : s = "ERROR_COULD_NOT_READ_FILE" ; break; case ERROR_DUPLICATED_EXTERNAL_VARIABLE : s = "ERROR_DUPLICATED_EXTERNAL_VARIABLE" ; break; case ERROR_INVALID_MODULE_DATA : s = "ERROR_INVALID_MODULE_DATA" ; break; case ERROR_WRITING_FILE : s = "ERROR_WRITING_FILE" ; break; case ERROR_INVALID_MODIFIER : s = "ERROR_INVALID_MODIFIER" ; break; case ERROR_DUPLICATED_MODIFIER : s = "ERROR_DUPLICATED_MODIFIER" ; break; case ERROR_BLOCK_NOT_READY : s = "ERROR_BLOCK_NOT_READY" ; break; } // clang-format on return s; } #endif #if defined(HAVE_LIBCRYPTO) && OPENSSL_VERSION_NUMBER < 0x10100000L // The OpenSSL library before version 1.1 requires some locks in order // to be thread-safe. These locks are initialized in yr_initialize // function. static YR_MUTEX *openssl_locks; static void _thread_id(CRYPTO_THREADID *id) { CRYPTO_THREADID_set_numeric(id, (unsigned long) yr_current_thread_id()); } static void _locking_function(int mode, int n, const char *file, int line) { if (mode & CRYPTO_LOCK) yr_mutex_lock(&openssl_locks[n]); else yr_mutex_unlock(&openssl_locks[n]); } #endif #if defined(HAVE_WINCRYPT_H) HCRYPTPROV yr_cryptprov; #endif //////////////////////////////////////////////////////////////////////////////// // Should be called by main thread before using any other // function from libyara. // YR_API int yr_initialize(void) { YR_DEBUG_FPRINTF(2, stderr, "+ %s() {\n", __FUNCTION__); uint32_t def_stack_size = DEFAULT_STACK_SIZE; uint32_t def_max_strings_per_rule = DEFAULT_MAX_STRINGS_PER_RULE; uint32_t def_max_match_data = DEFAULT_MAX_MATCH_DATA; uint64_t def_max_process_memory_chunk = DEFAULT_MAX_PROCESS_MEMORY_CHUNK; init_count++; if (init_count > 1) return ERROR_SUCCESS; // Initialize random number generator, as it is used for generating object // canaries. srand((unsigned) time(NULL)); for (int i = 0; i < 256; i++) { if (i >= 'a' && i <= 'z') yr_altercase[i] = i - 32; else if (i >= 'A' && i <= 'Z') yr_altercase[i] = i + 32; else yr_altercase[i] = i; yr_lowercase[i] = tolower(i); } FAIL_ON_ERROR(yr_heap_alloc()); FAIL_ON_ERROR(yr_thread_storage_create(&yr_yyfatal_trampoline_tls)); FAIL_ON_ERROR(yr_thread_storage_create(&yr_trycatch_trampoline_tls)); #if defined HAVE_LIBCRYPTO && OPENSSL_VERSION_NUMBER < 0x10100000L openssl_locks = (YR_MUTEX *) OPENSSL_malloc( CRYPTO_num_locks() * sizeof(YR_MUTEX)); for (int i = 0; i < CRYPTO_num_locks(); i++) yr_mutex_create(&openssl_locks[i]); CRYPTO_THREADID_set_callback(_thread_id); CRYPTO_set_locking_callback(_locking_function); #elif defined(HAVE_WINCRYPT_H) if (!CryptAcquireContext( &yr_cryptprov, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { return ERROR_INTERNAL_FATAL_ERROR; } #elif defined(HAVE_COMMON_CRYPTO) ... #endif FAIL_ON_ERROR(yr_modules_initialize()); // Initialize default configuration options FAIL_ON_ERROR(yr_set_configuration(YR_CONFIG_STACK_SIZE, &def_stack_size)); FAIL_ON_ERROR(yr_set_configuration( YR_CONFIG_MAX_STRINGS_PER_RULE, &def_max_strings_per_rule)); FAIL_ON_ERROR(yr_set_configuration( YR_CONFIG_MAX_PROCESS_MEMORY_CHUNK, &def_max_process_memory_chunk)); FAIL_ON_ERROR( yr_set_configuration(YR_CONFIG_MAX_MATCH_DATA, &def_max_match_data)); YR_DEBUG_FPRINTF(2, stderr, "} // %s()\n", __FUNCTION__); return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Should be called by main thread before exiting. // YR_API int yr_finalize(void) { YR_DEBUG_FPRINTF(2, stderr, "+ %s() {\n", __FUNCTION__); #if defined HAVE_LIBCRYPTO && OPENSSL_VERSION_NUMBER < 0x10100000L int i; #endif // yr_finalize shouldn't be called without calling yr_initialize first if (init_count == 0) return ERROR_INTERNAL_FATAL_ERROR; init_count--; if (init_count > 0) return ERROR_SUCCESS; #if defined HAVE_LIBCRYPTO && OPENSSL_VERSION_NUMBER < 0x10100000L for (i = 0; i < CRYPTO_num_locks(); i++) yr_mutex_destroy(&openssl_locks[i]); OPENSSL_free(openssl_locks); CRYPTO_THREADID_set_callback(NULL); CRYPTO_set_locking_callback(NULL); #elif defined(HAVE_WINCRYPT_H) CryptReleaseContext(yr_cryptprov, 0); #endif FAIL_ON_ERROR(yr_thread_storage_destroy(&yr_yyfatal_trampoline_tls)); FAIL_ON_ERROR(yr_thread_storage_destroy(&yr_trycatch_trampoline_tls)); FAIL_ON_ERROR(yr_modules_finalize()); FAIL_ON_ERROR(yr_heap_free()); #if defined(JEMALLOC) malloc_stats_print(NULL, NULL, NULL); mallctl("prof.dump", NULL, NULL, NULL, 0); #endif YR_DEBUG_FPRINTF(2, stderr, "} // %s()\n", __FUNCTION__); return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Set a configuration option. // // This function receives a configuration name, as defined by the YR_CONFIG_NAME // enum, and a pointer to the value being set. The type of the value depends on // the configuration name. // // The caller must ensure that the pointer passed to the function is the correct // type. Using yr_set_configuration_uintXX is preferred, as those functions will // perform the necessary type checking. // // Args: // name: Any of the values defined by the YR_CONFIG_NAME enum. Possible values // are: // YR_CONFIG_STACK_SIZE data type: uint32_t // YR_CONFIG_MAX_STRINGS_PER_RULE data type: uint32_t // YR_CONFIG_MAX_MATCH_DATA data type: uint32_t // YR_CONFIG_MAX_PROCESS_MEMORY_CHUNK data type: uint64_t // // src: Pointer to the value being set for the option. // // Returns: // ERROR_SUCCESS // ERROR_INVALID_ARGUMENT // YR_API int yr_set_configuration(YR_CONFIG_NAME name, void *src) { if (src == NULL) return ERROR_INTERNAL_FATAL_ERROR; switch (name) { // lump all the cases using same types together in one cascade case YR_CONFIG_STACK_SIZE: case YR_CONFIG_MAX_STRINGS_PER_RULE: case YR_CONFIG_MAX_MATCH_DATA: yr_cfgs[name].ui32 = *(uint32_t *) src; break; case YR_CONFIG_MAX_PROCESS_MEMORY_CHUNK: yr_cfgs[name].ui64 = *(uint64_t *) src; break; default: return ERROR_INTERNAL_FATAL_ERROR; } return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Set a configuration option. // // This function receives a configuration name, as defined by the YR_CONFIG_NAME // and a value for the configuration being set. Only configuration names with // type uint32_t will be accepted, if not ERROR_INVALID_ARGUMENT will be // returned. // // Returns: // ERROR_SUCCESS // ERROR_INVALID_ARGUMENT // YR_API int yr_set_configuration_uint32(YR_CONFIG_NAME name, uint32_t value) { switch (name) { // Accept only the configuration options that are of type uint32_t. case YR_CONFIG_STACK_SIZE: case YR_CONFIG_MAX_STRINGS_PER_RULE: case YR_CONFIG_MAX_MATCH_DATA: return yr_set_configuration(name, &value); default: return ERROR_INVALID_ARGUMENT; } } //////////////////////////////////////////////////////////////////////////////// // Set a configuration option. // // See yr_set_configuration_uint32 for more details. // YR_API int yr_set_configuration_uint64(YR_CONFIG_NAME name, uint64_t value) { switch (name) { case YR_CONFIG_MAX_PROCESS_MEMORY_CHUNK: return yr_set_configuration(name, &value); default: return ERROR_INVALID_ARGUMENT; } } //////////////////////////////////////////////////////////////////////////////// // Get a configuration option. // // This function receives a configuration name, as defined by the YR_CONFIG_NAME // enum, and a pointer to the variable that will receive the value for that // option. The type of the value depends on the configuration name. // // The caller must ensure that the pointer passed to the function is the correct // type. Using yr_get_configuration_uintXX is preferred. // // Args: // name: Any of the values defined by the YR_CONFIG_NAME enum. Possible values // are: // YR_CONFIG_STACK_SIZE data type: uint32_t // YR_CONFIG_MAX_STRINGS_PER_RULE data type: uint32_t // YR_CONFIG_MAX_MATCH_DATA data type: uint32_t // YR_CONFIG_MAX_PROCESS_MEMORY_CHUNK data type: uint64_t // // dest: Pointer to a variable that will receive the value for the option. // // Returns: // ERROR_SUCCESS // ERROR_INVALID_ARGUMENT // YR_API int yr_get_configuration(YR_CONFIG_NAME name, void *dest) { if (dest == NULL) return ERROR_INVALID_ARGUMENT; switch (name) { // lump all the cases using same types together in one cascade case YR_CONFIG_STACK_SIZE: case YR_CONFIG_MAX_STRINGS_PER_RULE: case YR_CONFIG_MAX_MATCH_DATA: *(uint32_t *) dest = yr_cfgs[name].ui32; break; case YR_CONFIG_MAX_PROCESS_MEMORY_CHUNK: *(uint64_t *) dest = yr_cfgs[name].ui64; break; default: return ERROR_INVALID_ARGUMENT; } return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Get a configuration option. // // This function receives a configuration name, as defined by the YR_CONFIG_NAME // and a value for the configuration being set. Only configuration names with // type uint32_t will be accepted, if not ERROR_INVALID_ARGUMENT will be // returned. // // Returns: // ERROR_SUCCESS // ERROR_INVALID_ARGUMENT // YR_API int yr_get_configuration_uint32(YR_CONFIG_NAME name, uint32_t *dest) { switch (name) { // Accept only the configuration options that are of type uint32_t. case YR_CONFIG_STACK_SIZE: case YR_CONFIG_MAX_STRINGS_PER_RULE: case YR_CONFIG_MAX_MATCH_DATA: return yr_get_configuration(name, (void *) dest); default: return ERROR_INVALID_ARGUMENT; } } //////////////////////////////////////////////////////////////////////////////// // Get a configuration option. // // See yr_get_configuration_uint64 for more details. // YR_API int yr_get_configuration_uint64(YR_CONFIG_NAME name, uint64_t *value) { switch (name) { case YR_CONFIG_MAX_PROCESS_MEMORY_CHUNK: return yr_get_configuration(name, (void *) value); default: return ERROR_INVALID_ARGUMENT; } }yara-4.5.3/libyara/mem.c000066400000000000000000000066171501365277300150470ustar00rootroot00000000000000/* Copyright (c) 2007-2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #if defined(_WIN32) || defined(__CYGWIN__) #include #include static HANDLE hHeap; int yr_heap_alloc(void) { hHeap = HeapCreate(0, 0x8000, 0); if (hHeap == NULL) return ERROR_INTERNAL_FATAL_ERROR; return ERROR_SUCCESS; } int yr_heap_free(void) { if (HeapDestroy(hHeap)) return ERROR_SUCCESS; else return ERROR_INTERNAL_FATAL_ERROR; } void* yr_calloc(size_t count, size_t size) { return (void*) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, count * size); } void* yr_malloc(size_t size) { return (void*) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, size); } void* yr_realloc(void* ptr, size_t size) { if (ptr == NULL) return (void*) HeapAlloc(hHeap, HEAP_ZERO_MEMORY, size); return (void*) HeapReAlloc(hHeap, HEAP_ZERO_MEMORY, ptr, size); } char* yr_strdup(const char* str) { size_t len = strlen(str); char* dup = (char*) yr_malloc(len + 1); if (dup == NULL) return NULL; memcpy(dup, str, len); dup[len] = '\0'; return (char*) dup; } char* yr_strndup(const char* str, size_t n) { size_t len = strnlen(str, n); char* dup = (char*) yr_malloc(len + 1); if (dup == NULL) return NULL; memcpy(dup, str, len); dup[len] = '\0'; return (char*) dup; } YR_API void yr_free(void* ptr) { HeapFree(hHeap, 0, ptr); } #else #include #include #include #if defined(MIMALLOC) #include #endif int yr_heap_alloc(void) { return ERROR_SUCCESS; } int yr_heap_free(void) { return ERROR_SUCCESS; } void* yr_calloc(size_t count, size_t size) { return calloc(count, size); } void* yr_malloc(size_t size) { return malloc(size); } void* yr_realloc(void* ptr, size_t size) { return realloc(ptr, size); } char* yr_strdup(const char* str) { return strdup(str); } char* yr_strndup(const char* str, size_t n) { return strndup(str, n); } YR_API void yr_free(void* ptr) { free(ptr); } #endif yara-4.5.3/libyara/modules.c000066400000000000000000000131201501365277300157240ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #define MODULE(name) \ int name##__declarations(YR_OBJECT* module); \ int name##__load( \ YR_SCAN_CONTEXT* context, \ YR_OBJECT* module, \ void* module_data, \ size_t module_data_size); \ int name##__unload(YR_OBJECT* main_structure); \ int name##__initialize(YR_MODULE* module); \ int name##__finalize(YR_MODULE* module); #include #undef MODULE #define MODULE(name) \ {#name, \ name##__declarations, \ name##__load, \ name##__unload, \ name##__initialize, \ name##__finalize}, YR_MODULE yr_modules_table[] = { #include {NULL, NULL, NULL, NULL, NULL, NULL}}; #undef MODULE int yr_modules_initialize() { for (YR_MODULE* module = yr_modules_table; module->initialize != NULL; module++) { int result = module->initialize(module); if (result != ERROR_SUCCESS) return result; } return ERROR_SUCCESS; } int yr_modules_finalize() { for (YR_MODULE* module = yr_modules_table; module->finalize != NULL; module++) { int result = module->finalize(module); if (result != ERROR_SUCCESS) return result; } return ERROR_SUCCESS; } int yr_modules_do_declarations( const char* module_name, YR_OBJECT* main_structure) { for (YR_MODULE* module = yr_modules_table; module->name != NULL && module->declarations != NULL; module++) { if (strcmp(module->name, module_name) == 0) return module->declarations(main_structure); } return ERROR_UNKNOWN_MODULE; } int yr_modules_load(const char* module_name, YR_SCAN_CONTEXT* context) { int result; YR_MODULE_IMPORT mi; YR_OBJECT* module_structure = (YR_OBJECT*) yr_hash_table_lookup( context->objects_table, module_name, NULL); // if module_structure != NULL, the module was already // loaded, return successfully without doing nothing. if (module_structure != NULL) return ERROR_SUCCESS; // not loaded yet FAIL_ON_ERROR(yr_object_create( OBJECT_TYPE_STRUCTURE, module_name, NULL, &module_structure)); // initialize canary for module's top-level structure, every other object // within the module inherits the same canary. yr_object_set_canary(module_structure, context->canary); mi.module_name = module_name; mi.module_data = NULL; mi.module_data_size = 0; result = context->callback( context, CALLBACK_MSG_IMPORT_MODULE, &mi, context->user_data); if (result == CALLBACK_ERROR) { yr_object_destroy(module_structure); return ERROR_CALLBACK_ERROR; } FAIL_ON_ERROR_WITH_CLEANUP( yr_modules_do_declarations(module_name, module_structure), yr_object_destroy(module_structure)); FAIL_ON_ERROR_WITH_CLEANUP( yr_hash_table_add( context->objects_table, module_name, NULL, module_structure), yr_object_destroy(module_structure)); for (YR_MODULE* module = yr_modules_table; module->name != NULL && module->load != NULL; module++) { if (strcmp(module->name, module_name) == 0) { result = module->load( context, module_structure, mi.module_data, mi.module_data_size); if (result != ERROR_SUCCESS) return result; } } result = context->callback( context, CALLBACK_MSG_MODULE_IMPORTED, module_structure, context->user_data); if (result == CALLBACK_ERROR) return ERROR_CALLBACK_ERROR; return ERROR_SUCCESS; } int yr_modules_unload_all(YR_SCAN_CONTEXT* context) { for (YR_MODULE* module = yr_modules_table; module->name != NULL && module->unload != NULL; module++) { YR_OBJECT* module_structure = (YR_OBJECT*) yr_hash_table_remove( context->objects_table, module->name, NULL); if (module_structure != NULL) { module->unload(module_structure); yr_object_destroy(module_structure); } } return ERROR_SUCCESS; } YR_MODULE* yr_modules_get_table(void) { return yr_modules_table; }yara-4.5.3/libyara/modules/000077500000000000000000000000001501365277300155635ustar00rootroot00000000000000yara-4.5.3/libyara/modules/console/000077500000000000000000000000001501365277300172255ustar00rootroot00000000000000yara-4.5.3/libyara/modules/console/console.c000066400000000000000000000173471501365277300210470ustar00rootroot00000000000000/* Copyright (c) 2021. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #define MODULE_NAME console define_function(log_string) { // We are intentionally using sized strings here as we may be needing to // output strings with a null character in the middle. SIZED_STRING* s = sized_string_argument(1); YR_SCAN_CONTEXT* ctx = yr_scan_context(); YR_CALLBACK_FUNC callback = ctx->callback; // Assume the entire string is non-printable, so allocate 4 times the // space so that we can represent each byte as an escaped value. eg: \x00 // Add an extra byte for the NULL terminator. char* msg; if (s->length == 0) { callback(ctx, CALLBACK_MSG_CONSOLE_LOG, (void*) "", ctx->user_data); return_integer(1); } else { msg = (char*) yr_calloc((s->length * 4) + 1, sizeof(char)); if (msg == NULL) return_integer(YR_UNDEFINED); } char* p = msg; for (size_t i = 0; i < s->length; i++) { if (isprint((unsigned char) s->c_string[i])) { *p++ = s->c_string[i]; } else { sprintf(p, "\\x%02x", (unsigned char) s->c_string[i]); p += 4; } } // result is ignored, as we have no way to signal to the library that it // should abort or continue. callback(ctx, CALLBACK_MSG_CONSOLE_LOG, (void*) msg, ctx->user_data); yr_free(msg); return_integer(1); } define_function(log_string_msg) { char* m = string_argument(1); // We are intentionally using sized strings here as we may be needing to // output strings with a null character in the middle. SIZED_STRING* s = sized_string_argument(2); YR_SCAN_CONTEXT* ctx = yr_scan_context(); YR_CALLBACK_FUNC callback = ctx->callback; // Assume the entire string is non-printable, so allocate 4 times the // space so that we can represent each byte as an escaped value. eg: \x00 // Add an extra byte for the NULL terminator. size_t msg_len = strlen(m) + (s->length * 4) + 1; char* msg = (char*) yr_calloc(msg_len, sizeof(char)); if (msg == NULL && msg_len > 0) return_integer(YR_UNDEFINED); char* p = msg; strlcpy(msg, m, msg_len); p += strlen(m); for (size_t i = 0; i < s->length; i++) { if (isprint((unsigned char) s->c_string[i])) { *p++ = s->c_string[i]; } else { sprintf(p, "\\x%02x", (unsigned char) s->c_string[i]); p += 4; } } // result is ignored, as we have no way to signal to the library that it // should abort or continue. callback(ctx, CALLBACK_MSG_CONSOLE_LOG, (void*) msg, ctx->user_data); yr_free(msg); return_integer(1); } define_function(log_integer) { char* msg = NULL; int64_t i = integer_argument(1); YR_SCAN_CONTEXT* ctx = yr_scan_context(); YR_CALLBACK_FUNC callback = ctx->callback; yr_asprintf(&msg, "%lli", i); if (msg == NULL) return_integer(YR_UNDEFINED); // result is ignored, as we have no way to signal to the library that it // should abort or continue. callback(ctx, CALLBACK_MSG_CONSOLE_LOG, (void*) msg, ctx->user_data); yr_free(msg); return_integer(1); } define_function(log_integer_msg) { char* msg = NULL; char* s = string_argument(1); int64_t i = integer_argument(2); YR_SCAN_CONTEXT* ctx = yr_scan_context(); YR_CALLBACK_FUNC callback = ctx->callback; yr_asprintf(&msg, "%s%lli", s, i); if (msg == NULL) return_integer(YR_UNDEFINED); // result is ignored, as we have no way to signal to the library that it // should abort or continue. callback(ctx, CALLBACK_MSG_CONSOLE_LOG, (void*) msg, ctx->user_data); yr_free(msg); return_integer(1); } define_function(log_float) { char* msg = NULL; double f = float_argument(1); YR_SCAN_CONTEXT* ctx = yr_scan_context(); YR_CALLBACK_FUNC callback = ctx->callback; yr_asprintf(&msg, "%f", f); if (msg == NULL) return_integer(YR_UNDEFINED); // result is ignored, as we have no way to signal to the library that it // should abort or continue. callback(ctx, CALLBACK_MSG_CONSOLE_LOG, (void*) msg, ctx->user_data); yr_free(msg); return_integer(1); } define_function(log_float_msg) { char* msg = NULL; char* s = string_argument(1); double f = float_argument(2); YR_SCAN_CONTEXT* ctx = yr_scan_context(); YR_CALLBACK_FUNC callback = ctx->callback; yr_asprintf(&msg, "%s%f", s, f); if (msg == NULL) return_integer(YR_UNDEFINED); // result is ignored, as we have no way to signal to the library that it // should abort or continue. callback(ctx, CALLBACK_MSG_CONSOLE_LOG, (void*) msg, ctx->user_data); yr_free(msg); return_integer(1); } define_function(hex_integer) { char* msg = NULL; int64_t i = integer_argument(1); YR_SCAN_CONTEXT* ctx = yr_scan_context(); YR_CALLBACK_FUNC callback = ctx->callback; yr_asprintf(&msg, "0x%llx", i); if (msg == NULL) return_integer(YR_UNDEFINED); // result is ignored, as we have no way to signal to the library that it // should abort or continue. callback(ctx, CALLBACK_MSG_CONSOLE_LOG, (void*) msg, ctx->user_data); yr_free(msg); return_integer(1); } define_function(hex_integer_msg) { char* msg = NULL; char* s = string_argument(1); int64_t i = integer_argument(2); YR_SCAN_CONTEXT* ctx = yr_scan_context(); YR_CALLBACK_FUNC callback = ctx->callback; yr_asprintf(&msg, "%s0x%llx", s, i); if (msg == NULL) return_integer(YR_UNDEFINED); // result is ignored, as we have no way to signal to the library that it // should abort or continue. callback(ctx, CALLBACK_MSG_CONSOLE_LOG, (void*) msg, ctx->user_data); yr_free(msg); return_integer(1); } begin_declarations declare_function("log", "s", "i", log_string); declare_function("log", "ss", "i", log_string_msg); declare_function("log", "i", "i", log_integer); declare_function("log", "si", "i", log_integer_msg); declare_function("log", "f", "i", log_float); declare_function("log", "sf", "i", log_float_msg); declare_function("hex", "i", "i", hex_integer); declare_function("hex", "si", "i", hex_integer_msg); end_declarations int module_initialize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_finalize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { return ERROR_SUCCESS; } int module_unload(YR_OBJECT* module_object) { return ERROR_SUCCESS; } yara-4.5.3/libyara/modules/cuckoo/000077500000000000000000000000001501365277300170465ustar00rootroot00000000000000yara-4.5.3/libyara/modules/cuckoo/cuckoo.c000066400000000000000000000254671501365277300205130ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #if defined(_WIN32) || defined(__CYGWIN__) #define strcasecmp _stricmp #endif #define MODULE_NAME cuckoo define_function(network_dns_lookup) { YR_SCAN_CONTEXT* context = yr_scan_context(); YR_OBJECT* network_obj = yr_parent(); json_t* network_json = (json_t*) network_obj->data; json_t* value; uint64_t result = 0; size_t index; // Recent versions of Cuckoo generate domain resolution information with // this format: // // "domains": [ // { // "ip": "192.168.0.1", // "domain": "foo.bar.com" // } // ] // // But older versions with this other format: // // "dns": [ // { // "ip": "192.168.0.1", // "hostname": "foo.bar.com" // } // ] // // Additionally, the newer versions also have a "dns" field. So, let's try // to locate the "domains" field first, if not found fall back to the older // format. char* field_name = "domain"; char* hostname; char* ip; json_t* dns_info_json = json_object_get(network_json, "domains"); if (dns_info_json == NULL) { dns_info_json = json_object_get(network_json, "dns"); field_name = "hostname"; } json_array_foreach(dns_info_json, index, value) { if (json_unpack(value, "{s:s, s:s}", "ip", &ip, field_name, &hostname) == 0) { if (yr_re_match(context, regexp_argument(1), hostname) > 0) { result = 1; break; } } } return_integer(result); } #define METHOD_GET 0x01 #define METHOD_POST 0x02 uint64_t http_request( YR_SCAN_CONTEXT* context, YR_OBJECT* network_obj, RE* uri_regexp, int methods) { json_t* network_json = (json_t*) network_obj->data; json_t* http_json = json_object_get(network_json, "http"); json_t* value; uint64_t result = 0; size_t index; char* method; char* uri; json_array_foreach(http_json, index, value) { if (json_unpack(value, "{s:s, s:s}", "uri", &uri, "method", &method) == 0) { if (((methods & METHOD_GET && strcasecmp(method, "get") == 0) || (methods & METHOD_POST && strcasecmp(method, "post") == 0)) && yr_re_match(context, uri_regexp, uri) > 0) { result = 1; break; } } } return result; } define_function(network_http_request) { return_integer(http_request( yr_scan_context(), yr_parent(), regexp_argument(1), METHOD_GET | METHOD_POST)); } define_function(network_http_get) { return_integer( http_request(yr_scan_context(), yr_parent(), regexp_argument(1), METHOD_GET)); } define_function(network_http_post) { return_integer( http_request(yr_scan_context(), yr_parent(), regexp_argument(1), METHOD_POST)); } // checks the host array in network JSON // loops through array and checks value for argument define_function(network_host) { YR_SCAN_CONTEXT* context = yr_scan_context(); YR_OBJECT* network_obj = yr_parent(); json_t* network_json = (json_t*) network_obj->data; json_t* value; uint64_t result = 0; size_t index; json_t* hosts_info_json = json_object_get(network_json, "hosts"); json_array_foreach(hosts_info_json, index, value) { if (yr_re_match(context, regexp_argument(1), json_string_value(value)) > 0) { result = 1; break; } } return_integer(result); } // loops through TCP array in network JSON // checks for dest IP regex and dest port integer match define_function(network_tcp) { YR_SCAN_CONTEXT* context = yr_scan_context(); YR_OBJECT* network_obj = yr_parent(); json_t* network_json = (json_t*) network_obj->data; json_t* value; uint64_t result = 0; size_t index; int dport; char* dst; json_t* tcp_info_json = json_object_get(network_json, "tcp"); json_array_foreach(tcp_info_json, index, value) { if (json_unpack(value, "{s:i, s:s}", "dport", &dport, "dst", &dst) == 0) { if (yr_re_match(context, regexp_argument(1), dst) > 0) { if ((int64_t) dport == integer_argument(2)) { result = 1; break; } } } } return_integer(result); } // loops through UDP array in network JSON // checks for dest IP regex and dest port integer match define_function(network_udp) { YR_SCAN_CONTEXT* context = yr_scan_context(); YR_OBJECT* network_obj = yr_parent(); json_t* network_json = (json_t*) network_obj->data; json_t* value; uint64_t result = 0; size_t index; int dport; char* dst; json_t* udp_info_json = json_object_get(network_json, "udp"); json_array_foreach(udp_info_json, index, value) { if (json_unpack(value, "{s:i, s:s}", "dport", &dport, "dst", &dst) == 0) { if (yr_re_match(context, regexp_argument(1), dst) > 0) { if ((int64_t) dport == integer_argument(2)) { result = 1; break; } } } } return_integer(result); } // loops through http array in network JSON // checks for regex match on user-agent define_function(network_http_user_agent) { YR_SCAN_CONTEXT* context = yr_scan_context(); YR_OBJECT* network_obj = yr_parent(); json_t* network_json = (json_t*) network_obj->data; json_t* http_json = json_object_get(network_json, "http"); json_t* value; uint64_t result = 0; size_t index; char* user_agent; json_array_foreach(http_json, index, value) { if (json_unpack(value, "{s:s}", "user-agent", &user_agent) == 0) { if (yr_re_match(context, regexp_argument(1), user_agent) > 0) { result = 1; break; } } } return_integer(result); } define_function(registry_key_access) { YR_SCAN_CONTEXT* context = yr_scan_context(); YR_OBJECT* registry_obj = yr_parent(); json_t* keys_json = (json_t*) registry_obj->data; json_t* value; uint64_t result = 0; size_t index; json_array_foreach(keys_json, index, value) { if (yr_re_match(context, regexp_argument(1), json_string_value(value)) > 0) { result = 1; break; } } return_integer(result); } define_function(filesystem_file_access) { YR_SCAN_CONTEXT* context = yr_scan_context(); YR_OBJECT* filesystem_obj = yr_parent(); json_t* files_json = (json_t*) filesystem_obj->data; json_t* value; uint64_t result = 0; size_t index; json_array_foreach(files_json, index, value) { if (yr_re_match(context, regexp_argument(1), json_string_value(value)) > 0) { result = 1; break; } } return_integer(result); } define_function(sync_mutex) { YR_SCAN_CONTEXT* context = yr_scan_context(); YR_OBJECT* sync_obj = yr_parent(); json_t* mutexes_json = (json_t*) sync_obj->data; json_t* value; uint64_t result = 0; size_t index; json_array_foreach(mutexes_json, index, value) { if (yr_re_match(context, regexp_argument(1), json_string_value(value)) > 0) { result = 1; break; } } return_integer(result); } begin_declarations begin_struct("network") declare_function("dns_lookup", "r", "i", network_dns_lookup); declare_function("http_get", "r", "i", network_http_get); declare_function("http_post", "r", "i", network_http_post); declare_function("http_request", "r", "i", network_http_request); declare_function("http_user_agent", "r", "i", network_http_user_agent); declare_function("host", "r", "i", network_host); declare_function("tcp", "ri", "i", network_tcp); declare_function("udp", "ri", "i", network_udp); end_struct("network") begin_struct("registry") declare_function("key_access", "r", "i", registry_key_access); end_struct("registry") begin_struct("filesystem") declare_function("file_access", "r", "i", filesystem_file_access); end_struct("filesystem") begin_struct("sync") declare_function("mutex", "r", "i", sync_mutex) end_struct("sync") end_declarations int module_initialize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_finalize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { YR_OBJECT* network_obj; YR_OBJECT* registry_obj; YR_OBJECT* filesystem_obj; YR_OBJECT* sync_obj; json_error_t json_error; json_t* summary_json; json_t* json; if (module_data == NULL) return ERROR_SUCCESS; json = json_loadb( (const char*) module_data, module_data_size, #if JANSSON_VERSION_HEX >= 0x020600 JSON_ALLOW_NUL, #else 0, #endif &json_error); if (json == NULL) return ERROR_INVALID_MODULE_DATA; module_object->data = (void*) json; network_obj = yr_get_object(module_object, "network"); registry_obj = yr_get_object(module_object, "registry"); filesystem_obj = yr_get_object(module_object, "filesystem"); sync_obj = yr_get_object(module_object, "sync"); network_obj->data = (void*) json_object_get(json, "network"); json = json_object_get(json, "behavior"); summary_json = json_object_get(json, "summary"); registry_obj->data = (void*) json_object_get(summary_json, "keys"); filesystem_obj->data = (void*) json_object_get(summary_json, "files"); sync_obj->data = (void*) json_object_get(summary_json, "mutexes"); return ERROR_SUCCESS; } int module_unload(YR_OBJECT* module) { if (module->data != NULL) json_decref((json_t*) module->data); return ERROR_SUCCESS; } yara-4.5.3/libyara/modules/demo/000077500000000000000000000000001501365277300165075ustar00rootroot00000000000000yara-4.5.3/libyara/modules/demo/demo.c000066400000000000000000000040001501365277300175710ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #define MODULE_NAME demo begin_declarations declare_string("greeting"); end_declarations int module_initialize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_finalize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { yr_set_string("Hello World!", module_object, "greeting"); return ERROR_SUCCESS; } int module_unload(YR_OBJECT* module_object) { return ERROR_SUCCESS; } yara-4.5.3/libyara/modules/dex/000077500000000000000000000000001501365277300163435ustar00rootroot00000000000000yara-4.5.3/libyara/modules/dex/dex.c000066400000000000000000001301431501365277300172710ustar00rootroot00000000000000/* Copyright (c) 2018. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #define MODULE_NAME dex // DEX File layout information: // https://source.android.com/devices/tech/dalvik/dex-format define_function(has_method_string) { SIZED_STRING* parsed_name; SIZED_STRING* method_name = sized_string_argument(1); YR_OBJECT* module = yr_module(); int64_t number_of_methods = yr_get_integer(module, "number_of_methods"); if (number_of_methods == YR_UNDEFINED) return_integer(YR_UNDEFINED); for (int i = 0; i < number_of_methods; i++) { parsed_name = yr_get_string(module, "method[%i].name", i); if (parsed_name != NULL && strcmp(parsed_name->c_string, method_name->c_string) == 0) { return_integer(1); } } return_integer(0); } define_function(has_method_and_class_string) { SIZED_STRING* parsed_class; SIZED_STRING* parsed_name; SIZED_STRING* class_name = sized_string_argument(1); SIZED_STRING* method_name = sized_string_argument(2); YR_OBJECT* module = yr_module(); int64_t number_of_methods = yr_get_integer(module, "number_of_methods"); if (number_of_methods == YR_UNDEFINED) return_integer(YR_UNDEFINED); for (int i = 0; i < number_of_methods; i++) { parsed_class = yr_get_string(module, "method[%i].class_name", i); if (parsed_class != NULL && strcmp(parsed_class->c_string, class_name->c_string) != 0) { continue; } parsed_name = yr_get_string(module, "method[%i].name", i); if (parsed_name != NULL && strcmp(parsed_name->c_string, method_name->c_string) == 0) { return_integer(1); } } return_integer(0); } define_function(has_method_regexp) { SIZED_STRING* parsed_name; RE* regex = regexp_argument(1); YR_OBJECT* module = yr_module(); int64_t number_of_methods = yr_get_integer(module, "number_of_methods"); if (number_of_methods == YR_UNDEFINED) return_integer(YR_UNDEFINED); for (int i = 0; i < number_of_methods; i++) { parsed_name = yr_get_string(module, "method[%i].name", i); if (parsed_name != NULL && yr_re_match(yr_scan_context(), regex, parsed_name->c_string) != -1) { return_integer(1); } } return_integer(0); } define_function(has_method_and_class_regexp) { SIZED_STRING* parsed_class; SIZED_STRING* parsed_name; RE* class_regex = regexp_argument(1); RE* name_regex = regexp_argument(2); YR_OBJECT* module = yr_module(); int64_t number_of_methods = yr_get_integer(module, "number_of_methods"); if (number_of_methods == YR_UNDEFINED) return_integer(YR_UNDEFINED); for (int i = 0; i < number_of_methods; i++) { parsed_class = yr_get_string(module, "method[%i].class_name", i); if (parsed_class != NULL && yr_re_match(yr_scan_context(), class_regex, parsed_class->c_string) == -1) { continue; } parsed_name = yr_get_string(module, "method[%i].name", i); if (parsed_name != NULL && yr_re_match(yr_scan_context(), name_regex, parsed_name->c_string) != -1) { return_integer(1); } } return_integer(0); } define_function(has_class_string) { SIZED_STRING* parsed_class; SIZED_STRING* class_name = sized_string_argument(1); YR_OBJECT* module = yr_module(); int64_t number_of_methods = yr_get_integer(module, "number_of_methods"); if (number_of_methods == YR_UNDEFINED) return_integer(YR_UNDEFINED); for (int i = 0; i < number_of_methods; i++) { parsed_class = yr_get_string(module, "method[%i].class_name", i); if (parsed_class != NULL && strcmp(parsed_class->c_string, class_name->c_string) == 0) { return_integer(1); } } return_integer(0); } define_function(has_class_regexp) { SIZED_STRING* parsed_class; RE* regex = regexp_argument(1); YR_OBJECT* module = yr_module(); int64_t number_of_methods = yr_get_integer(module, "number_of_methods"); if (number_of_methods == YR_UNDEFINED) return_integer(YR_UNDEFINED); for (int i = 0; i < number_of_methods; i++) { parsed_class = yr_get_string(module, "method[%i].class_name", i); if (parsed_class != NULL && yr_re_match(yr_scan_context(), regex, parsed_class->c_string) != -1) { return_integer(1); } } return_integer(0); } begin_declarations declare_string("DEX_FILE_MAGIC_035"); declare_string("DEX_FILE_MAGIC_036"); declare_string("DEX_FILE_MAGIC_037"); declare_string("DEX_FILE_MAGIC_038"); declare_string("DEX_FILE_MAGIC_039"); declare_integer("ENDIAN_CONSTANT"); declare_integer("REVERSE_ENDIAN_CONSTANT"); declare_integer("NO_INDEX"); declare_integer("ACC_PUBLIC"); declare_integer("ACC_PRIVATE"); declare_integer("ACC_PROTECTED"); declare_integer("ACC_STATIC"); declare_integer("ACC_FINAL"); declare_integer("ACC_SYNCHRONIZED"); declare_integer("ACC_VOLATILE"); declare_integer("ACC_BRIDGE"); declare_integer("ACC_TRANSIENT"); declare_integer("ACC_VARARGS"); declare_integer("ACC_NATIVE"); declare_integer("ACC_INTERFACE"); declare_integer("ACC_ABSTRACT"); declare_integer("ACC_STRICT"); declare_integer("ACC_SYNTHETIC"); declare_integer("ACC_ANNOTATION"); declare_integer("ACC_ENUM"); declare_integer("ACC_CONSTRUCTOR"); declare_integer("ACC_DECLARED_SYNCHRONIZED"); declare_integer("TYPE_HEADER_ITEM"); declare_integer("TYPE_STRING_ID_ITEM"); declare_integer("TYPE_TYPE_ID_ITEM"); declare_integer("TYPE_PROTO_ID_ITEM"); declare_integer("TYPE_FIELD_ID_ITEM"); declare_integer("TYPE_METHOD_ID_ITEM"); declare_integer("TYPE_CLASS_DEF_ITEM"); declare_integer("TYPE_CALL_SITE_ID_ITEM"); declare_integer("TYPE_METHOD_HANDLE_ITEM"); declare_integer("TYPE_MAP_LIST"); declare_integer("TYPE_TYPE_LIST"); declare_integer("TYPE_ANNOTATION_SET_REF_LIST"); declare_integer("TYPE_ANNOTATION_SET_ITEM"); declare_integer("TYPE_CLASS_DATA_ITEM"); declare_integer("TYPE_CODE_ITEM"); declare_integer("TYPE_STRING_DATA_ITEM"); declare_integer("TYPE_DEBUG_INFO_ITEM"); declare_integer("TYPE_ANNOTATION_ITEM"); declare_integer("TYPE_ENCODED_ARRAY_ITEM"); declare_integer("TYPE_ANNOTATIONS_DIRECTORY_ITEM"); begin_struct("header") declare_string("magic"); declare_integer("checksum"); declare_string("signature"); declare_integer("file_size"); declare_integer("header_size"); declare_integer("endian_tag"); declare_integer("link_size"); declare_integer("link_offset"); declare_integer("map_offset"); declare_integer("string_ids_size"); declare_integer("string_ids_offset"); declare_integer("type_ids_size"); declare_integer("type_ids_offset"); declare_integer("proto_ids_size"); declare_integer("proto_ids_offset"); declare_integer("field_ids_size"); declare_integer("field_ids_offset"); declare_integer("method_ids_size"); declare_integer("method_ids_offset"); declare_integer("class_defs_size"); declare_integer("class_defs_offset"); declare_integer("data_size"); declare_integer("data_offset"); end_struct("header") begin_struct_array("string_ids") declare_integer("offset"); declare_integer("size"); declare_string("value"); end_struct_array("string_ids") begin_struct_array("type_ids") declare_integer("descriptor_idx"); end_struct_array("type_ids") begin_struct_array("proto_ids") declare_integer("shorty_idx"); declare_integer("return_type_idx"); declare_integer("parameters_offset"); end_struct_array("proto_ids") begin_struct_array("field_ids") declare_integer("class_idx"); declare_integer("type_idx"); declare_integer("name_idx"); end_struct_array("field_ids") begin_struct_array("method_ids") declare_integer("class_idx"); declare_integer("proto_idx"); declare_integer("name_idx"); end_struct_array("method_ids") begin_struct_array("class_defs") declare_integer("class_idx"); declare_integer("access_flags"); declare_integer("super_class_idx"); declare_integer("interfaces_offset"); declare_integer("source_file_idx"); declare_integer("annotations_offset"); declare_integer("class_data_offset"); declare_integer("static_values_offset"); end_struct_array("class_defs") begin_struct_array("class_data_item") declare_integer("static_fields_size"); declare_integer("instance_fields_size"); declare_integer("direct_methods_size"); declare_integer("virtual_methods_size"); end_struct_array("class_data_item") begin_struct("map_list") declare_integer("size"); begin_struct_array("map_item") declare_integer("type"); declare_integer("unused"); declare_integer("size"); declare_integer("offset"); end_struct_array("map_item"); end_struct("map_list") declare_integer("number_of_fields"); begin_struct_array("field") declare_string("class_name"); declare_string("name"); declare_string("proto"); declare_integer("static"); declare_integer("instance"); declare_integer("field_idx_diff"); declare_integer("access_flags"); end_struct_array("field") declare_function("has_method", "s", "i", has_method_string); declare_function("has_method", "ss", "i", has_method_and_class_string); declare_function("has_method", "r", "i", has_method_regexp); declare_function("has_method", "rr", "i", has_method_and_class_regexp); declare_function("has_class", "s", "i", has_class_string); declare_function("has_class", "r", "i", has_class_regexp); declare_integer("number_of_methods"); begin_struct_array("method") declare_string("class_name"); declare_string("name"); declare_string("proto"); declare_integer("direct"); declare_integer("virtual"); declare_integer("method_idx_diff"); declare_integer("access_flags"); declare_integer("code_off"); begin_struct("code_item") declare_integer("registers_size"); declare_integer("ins_size"); declare_integer("outs_size"); declare_integer("tries_size"); declare_integer("debug_info_off"); declare_integer("insns_size"); declare_string("insns"); end_struct("code_item") end_struct_array("method") end_declarations // https://android.googlesource.com/platform/dalvik/+/android-4.4.2_r2/libdex/Leb128.cpp static int32_t read_uleb128_bounded( const uint8_t* pStream, const uint8_t* pStreamEnd, uint32_t* size, bool* error) { const uint8_t* ptr = pStream; int32_t result = 0; *error = false; if (ptr == pStreamEnd) goto error; result = *(ptr++); *size = *size + 1; if (result > 0x7f) { if (ptr == pStreamEnd) goto error; int cur = *(ptr++); *size = *size + 1; result = (result & 0x7f) | ((cur & 0x7f) << 7); if (cur > 0x7f) { if (ptr == pStreamEnd) goto error; cur = *(ptr++); *size = *size + 1; result |= (cur & 0x7f) << 14; if (cur > 0x7f) { if (ptr == pStreamEnd) goto error; cur = *(ptr++); *size = *size + 1; result |= (cur & 0x7f) << 21; if (cur > 0x7f) { if (ptr == pStreamEnd) goto error; /* * Note: We don't check to see if cur is out of * range here, meaning we tolerate garbage in the * high four-order bits. */ cur = *ptr; *size = *size + 1; result |= cur << 28; } } } } return result; error: *error = true; return result; } static int64_t dex_get_integer( YR_OBJECT* object, const char* pattern, int64_t index) { if (index == YR_UNDEFINED || index < 0) return YR_UNDEFINED; // Impose a reasonably large limit to table indexes. if (index > 0x80000) return YR_UNDEFINED; return yr_get_integer(object, pattern, (int) index); } static SIZED_STRING* dex_get_string( YR_OBJECT* object, const char* pattern, int64_t index) { if (index == YR_UNDEFINED || index < 0) return NULL; // Impose a reasonably large limit to table indexes. if (index > 0x80000) return NULL; return yr_get_string(object, pattern, (int) index); } dex_header_t* dex_get_header(const uint8_t* data, size_t data_size) { dex_header_t* dex_header; if (data_size < sizeof(dex_header_t)) return NULL; // Check if we have a valid DEX file dex_header = (dex_header_t*) data; if (memcmp(dex_header->magic, DEX_FILE_MAGIC_035, 8) != 0 && memcmp(dex_header->magic, DEX_FILE_MAGIC_036, 8) != 0 && memcmp(dex_header->magic, DEX_FILE_MAGIC_037, 8) != 0 && memcmp(dex_header->magic, DEX_FILE_MAGIC_038, 8) != 0 && memcmp(dex_header->magic, DEX_FILE_MAGIC_039, 8) != 0) { return NULL; } return dex_header; } void dex_parse_header(dex_header_t* dex_header, YR_OBJECT* module_object) { yr_set_sized_string( (char*) dex_header->magic, 8, module_object, "header.magic"); yr_set_integer( yr_le32toh(dex_header->checksum), module_object, "header.checksum"); yr_set_sized_string( (char*) dex_header->signature, 20, module_object, "header.signature"); yr_set_integer( yr_le32toh(dex_header->file_size), module_object, "header.file_size"); yr_set_integer( yr_le32toh(dex_header->header_size), module_object, "header.header_size"); yr_set_integer( yr_le32toh(dex_header->endian_tag), module_object, "header.endian_tag"); yr_set_integer( yr_le32toh(dex_header->link_size), module_object, "header.link_size"); yr_set_integer( yr_le32toh(dex_header->link_offset), module_object, "header.link_offset"); yr_set_integer( yr_le32toh(dex_header->map_offset), module_object, "header.map_offset"); yr_set_integer( yr_le32toh(dex_header->string_ids_size), module_object, "header.string_ids_size"); yr_set_integer( yr_le32toh(dex_header->string_ids_offset), module_object, "header.string_ids_offset"); yr_set_integer( yr_le32toh(dex_header->type_ids_size), module_object, "header.type_ids_size"); yr_set_integer( yr_le32toh(dex_header->type_ids_offset), module_object, "header.type_ids_offset"); yr_set_integer( yr_le32toh(dex_header->proto_ids_size), module_object, "header.proto_ids_size"); yr_set_integer( yr_le32toh(dex_header->proto_ids_offset), module_object, "header.proto_ids_offset"); yr_set_integer( yr_le32toh(dex_header->field_ids_size), module_object, "header.field_ids_size"); yr_set_integer( yr_le32toh(dex_header->field_ids_offset), module_object, "header.field_ids_offset"); yr_set_integer( yr_le32toh(dex_header->method_ids_size), module_object, "header.method_ids_size"); yr_set_integer( yr_le32toh(dex_header->method_ids_offset), module_object, "header.method_ids_offset"); yr_set_integer( yr_le32toh(dex_header->class_defs_size), module_object, "header.class_defs_size"); yr_set_integer( yr_le32toh(dex_header->class_defs_offset), module_object, "header.class_defs_offset"); yr_set_integer( yr_le32toh(dex_header->data_size), module_object, "header.data_size"); yr_set_integer( yr_le32toh(dex_header->data_offset), module_object, "header.data_offset"); } uint32_t load_encoded_field( DEX* dex, size_t start_offset, uint32_t* previous_field_idx, int index_encoded_field, int static_field, int instance_field) { #ifdef DEBUG_DEX_MODULE printf("[DEX] Parse encoded field start_offset:0x%zx\n", start_offset); #endif const uint8_t* data_cur_start = dex->data + start_offset; if (!fits_in_dex(dex, dex->data + start_offset, sizeof(uint32_t) * 2)) return 0; const uint8_t* data_end = dex->data + dex->data_size; uint32_t current_size = 0; bool error = false; encoded_field_t encoded_field; encoded_field.field_idx_diff = (uint32_t) read_uleb128_bounded((dex->data + start_offset + current_size), data_end, ¤t_size, &error); if (error) return 0; encoded_field.access_flags = (uint32_t) read_uleb128_bounded((dex->data + start_offset + current_size), data_end, ¤t_size, &error); if (error) return 0; yr_set_integer( encoded_field.field_idx_diff, dex->object, "field[%i].field_idx_diff", index_encoded_field); yr_set_integer( encoded_field.access_flags, dex->object, "field[%i].access_flags", index_encoded_field); yr_set_integer( static_field, dex->object, "field[%i].static", index_encoded_field); yr_set_integer( instance_field, dex->object, "field[%i].instance", index_encoded_field); *previous_field_idx = encoded_field.field_idx_diff + *previous_field_idx; #ifdef DEBUG_DEX_MODULE printf( "[DEX]\tEncoded field field_idx:0x%x field_idx_diff:0x%x " "access_flags:0x%x\n", *previous_field_idx, encoded_field.field_idx_diff, encoded_field.access_flags); #endif int64_t name_idx = dex_get_integer( dex->object, "field_ids[%i].name_idx", *previous_field_idx); if (name_idx == YR_UNDEFINED) return 0; SIZED_STRING* field_name = dex_get_string( dex->object, "string_ids[%i].value", name_idx); if (field_name != NULL) { #ifdef DEBUG_DEX_MODULE printf( "[DEX]\tFIELD_NAME %s NAME_IDX 0x%llx\n", field_name->c_string, name_idx); #endif yr_set_sized_string( field_name->c_string, field_name->length, dex->object, "field[%i].name", index_encoded_field); } int64_t class_idx = dex_get_integer( dex->object, "field_ids[%i].class_idx", *previous_field_idx); int64_t descriptor_idx = dex_get_integer( dex->object, "type_ids[%i].descriptor_idx", class_idx); SIZED_STRING* class_name = dex_get_string( dex->object, "string_ids[%i].value", descriptor_idx); if (class_name != NULL) { #ifdef DEBUG_DEX_MODULE printf( "[DEX]\tCLASS_NAME %s CLASS_IDX 0x%llx DESCRIPTOR_IDX 0x%llx\n", class_name->c_string, class_idx, descriptor_idx); #endif yr_set_sized_string( class_name->c_string, class_name->length, dex->object, "field[%i].class_name", index_encoded_field); } int type_idx = dex_get_integer( dex->object, "field_ids[%i].type_idx", *previous_field_idx); int shorty_idx = dex_get_integer( dex->object, "type_ids[%i].descriptor_idx", type_idx); SIZED_STRING* proto_name = dex_get_string( dex->object, "string_ids[%i].value", shorty_idx); if (proto_name != NULL) { #ifdef DEBUG_DEX_MODULE printf( "[DEX]\tPROTO_NAME %s TYPE_IDX 0x%x SHORTY_IDX 0x%x\n", proto_name->c_string, type_idx, shorty_idx); #endif yr_set_sized_string( proto_name->c_string, proto_name->length, dex->object, "field[%i].proto", index_encoded_field); } return current_size; } uint32_t load_encoded_method( DEX* dex, size_t start_offset, uint32_t* previous_method_idx, int index_encoded_method, int direct_method, int virtual_method) { #ifdef DEBUG_DEX_MODULE printf("[DEX] Parse encoded method start_offset:0x%zx\n", start_offset); #endif const uint8_t* data_cur_start = dex->data + start_offset; if (!fits_in_dex(dex, data_cur_start, sizeof(uint32_t) * 3)) return 0; const uint8_t* data_end = dex->data + dex->data_size; uint32_t current_size = 0; bool error = false; encoded_method_t encoded_method; encoded_method.method_idx_diff = (uint32_t) read_uleb128_bounded( (data_cur_start + current_size), data_end, ¤t_size, &error); if (error) return 0; encoded_method.access_flags = (uint32_t) read_uleb128_bounded( (data_cur_start + current_size), data_end, ¤t_size, &error); if (error) return 0; encoded_method.code_off = (uint32_t) read_uleb128_bounded( (data_cur_start + current_size), data_end, ¤t_size, &error); if (error) return 0; yr_set_integer( encoded_method.method_idx_diff, dex->object, "method[%i].method_idx_diff", index_encoded_method); yr_set_integer( encoded_method.access_flags, dex->object, "method[%i].access_flags", index_encoded_method); yr_set_integer( encoded_method.code_off, dex->object, "method[%i].code_off", index_encoded_method); yr_set_integer( direct_method, dex->object, "method[%i].direct", index_encoded_method); yr_set_integer( virtual_method, dex->object, "method[%i].virtual", index_encoded_method); *previous_method_idx = encoded_method.method_idx_diff + *previous_method_idx; int64_t name_idx = dex_get_integer( dex->object, "method_ids[%i].name_idx", *previous_method_idx); if (name_idx == YR_UNDEFINED) return 0; #ifdef DEBUG_DEX_MODULE printf("[DEX]\tNAME_IDX 0x%llx\n", name_idx); #endif #ifdef DEBUG_DEX_MODULE printf( "[DEX]\tEncoded method method_idx:0x%x method_idx_diff:0x%x " "access_flags:0x%x code_off:0x%x\n", *previous_method_idx, encoded_method.method_idx_diff, encoded_method.access_flags, encoded_method.code_off); #endif SIZED_STRING* method_name = dex_get_string( dex->object, "string_ids[%i].value", name_idx); if (method_name != NULL) { #ifdef DEBUG_DEX_MODULE printf( "[DEX]\tMETHOD_NAME %s NAME_IDX 0x%llx\n", method_name->c_string, name_idx); #endif yr_set_sized_string( method_name->c_string, method_name->length, dex->object, "method[%i].name", index_encoded_method); } int64_t class_idx = dex_get_integer( dex->object, "method_ids[%i].class_idx", *previous_method_idx); int64_t descriptor_idx = dex_get_integer( dex->object, "type_ids[%i].descriptor_idx", class_idx); SIZED_STRING* class_name = dex_get_string( dex->object, "string_ids[%i].value", descriptor_idx); if (class_name != NULL) { #ifdef DEBUG_DEX_MODULE printf( "[DEX]\tCLASS_NAME %s CLASS_IDX 0x%llx DESCRIPTOR_IDX:0x%llx\n", class_name->c_string, class_idx, descriptor_idx); #endif yr_set_sized_string( class_name->c_string, class_name->length, dex->object, "method[%i].class_name", index_encoded_method); } int64_t proto_idx = dex_get_integer( dex->object, "method_ids[%i].proto_idx", *previous_method_idx); int64_t shorty_idx = dex_get_integer( dex->object, "proto_ids[%i].shorty_idx", proto_idx); SIZED_STRING* proto_name = dex_get_string( dex->object, "string_ids[%i].value", shorty_idx); if (proto_name != NULL) { #ifdef DEBUG_DEX_MODULE printf( "[DEX]\tPROTO_NAME %s CLASS_IDX 0x%llx DESCRIPTOR_IDX:0x%llx\n", proto_name->c_string, class_idx, descriptor_idx); #endif yr_set_sized_string( proto_name->c_string, proto_name->length, dex->object, "method[%i].proto", index_encoded_method); } if (encoded_method.code_off != 0) { #ifdef DEBUG_DEX_MODULE printf("[DEX]\t\tParse CODE item\n"); #endif if (struct_fits_in_dex( dex, dex->data + encoded_method.code_off, code_item_t)) { code_item_t* code_item = (code_item_t*) (dex->data + encoded_method.code_off); yr_set_integer( code_item->registers_size, dex->object, "method[%i].code_item.registers_size", index_encoded_method); yr_set_integer( code_item->ins_size, dex->object, "method[%i].code_item.ins_size", index_encoded_method); yr_set_integer( code_item->outs_size, dex->object, "method[%i].code_item.outs_size", index_encoded_method); yr_set_integer( code_item->tries_size, dex->object, "method[%i].code_item.tries_size", index_encoded_method); yr_set_integer( code_item->debug_info_off, dex->object, "method[%i].code_item.debug_info_off", index_encoded_method); yr_set_integer( code_item->insns_size, dex->object, "method[%i].code_item.insns_size", index_encoded_method); if (fits_in_dex( dex, dex->data + encoded_method.code_off + sizeof(code_item_t), code_item->insns_size * 2)) { yr_set_sized_string( (const char*) (dex->data + encoded_method.code_off + sizeof(code_item_t)), code_item->insns_size * 2, dex->object, "method[%i].code_item.insns", index_encoded_method); } } } return current_size; } void dex_parse(DEX* dex, uint64_t base_address) { dex_header_t* dex_header; int i, j; uint32_t uleb128_size = 0; uint32_t new_size = 0; uint32_t index_class_data_item = 0; uint32_t index_encoded_method = 0; uint32_t index_encoded_field = 0; const uint8_t* data_end = dex->data + dex->data_size; if (!struct_fits_in_dex(dex, dex->data, dex_header_t)) return; dex_parse_header(dex->header, dex->object); dex_header = dex->header; if (!fits_in_dex( dex, dex->data + yr_le32toh(dex_header->string_ids_offset), yr_le32toh(dex_header->string_ids_size) * sizeof(string_id_item_t))) return; #ifdef DEBUG_DEX_MODULE printf("[DEX] Parse STRING ID section\n"); #endif // Get information about the String ID section for (i = 0; i < yr_le32toh(dex_header->string_ids_size); i++) { string_id_item_t* string_id_item = (string_id_item_t*) (dex->data + yr_le32toh(dex_header->string_ids_offset) + i * sizeof(string_id_item_t)); #ifdef DEBUG_DEX_MODULE printf( "[DEX] STRING ID item data_offset:0x%x\n", yr_le32toh(string_id_item->string_data_offset)); #endif if (!fits_in_dex( dex, dex->data + yr_le32toh(string_id_item->string_data_offset), sizeof(uint32_t))) continue; bool error = false; uint32_t value = (uint32_t) read_uleb128_bounded( (dex->data + yr_le32toh(string_id_item->string_data_offset)), data_end, &uleb128_size, &error); if (error) continue; #ifdef DEBUG_DEX_MODULE printf("[DEX] STRING ID item size:0x%x\n", value); #endif if (!fits_in_dex( dex, dex->data + yr_le32toh(string_id_item->string_data_offset) + 1, value)) continue; yr_set_integer( yr_le32toh(string_id_item->string_data_offset), dex->object, "string_ids[%i].offset", i); yr_set_integer(value, dex->object, "string_ids[%i].size", i); yr_set_sized_string( (const char*) ( dex->data + yr_le32toh(string_id_item->string_data_offset) + 1), value, dex->object, "string_ids[%i].value", i); } if (!fits_in_dex( dex, dex->data + yr_le32toh(dex_header->type_ids_offset), yr_le32toh(dex_header->type_ids_size) * sizeof(type_id_item_t))) return; #ifdef DEBUG_DEX_MODULE printf("[DEX] Parse TYPE ID section\n"); #endif // Get information about the Type ID section for (i = 0; i < yr_le32toh(dex_header->type_ids_size); i++) { type_id_item_t* type_id_item = (type_id_item_t*) (dex->data + yr_le32toh(dex_header->type_ids_offset) + i * sizeof(type_id_item_t)); yr_set_integer( yr_le32toh(type_id_item->descriptor_idx), dex->object, "type_ids[%i].descriptor_idx", i); } if (!fits_in_dex( dex, dex->data + yr_le32toh(dex_header->proto_ids_offset), yr_le32toh(dex_header->proto_ids_size) * sizeof(proto_id_item_t))) return; #ifdef DEBUG_DEX_MODULE printf("[DEX] Parse PROTO ID section\n"); #endif // Get information about the Proto ID section for (i = 0; i < yr_le32toh(dex_header->proto_ids_size); i++) { proto_id_item_t* proto_id_item = (proto_id_item_t*) (dex->data + yr_le32toh(dex_header->proto_ids_offset) + i * sizeof(proto_id_item_t)); yr_set_integer( yr_le32toh(proto_id_item->shorty_idx), dex->object, "proto_ids[%i].shorty_idx", i); yr_set_integer( yr_le32toh(proto_id_item->return_type_idx), dex->object, "proto_ids[%i].return_type_idx", i); yr_set_integer( yr_le32toh(proto_id_item->parameters_offset), dex->object, "proto_ids[%i].parameters_offset", i); } if (!fits_in_dex( dex, dex->data + yr_le32toh(dex_header->field_ids_offset), yr_le32toh(dex_header->field_ids_size) * sizeof(field_id_item_t))) return; #ifdef DEBUG_DEX_MODULE printf("[DEX] Parse FIELD ID section\n"); #endif // Get information about the Field ID section for (i = 0; i < yr_le32toh(dex_header->field_ids_size); i++) { field_id_item_t* field_id_item = (field_id_item_t*) (dex->data + yr_le32toh(dex_header->field_ids_offset) + i * sizeof(field_id_item_t)); yr_set_integer( yr_le16toh(field_id_item->class_idx), dex->object, "field_ids[%i].class_idx", i); yr_set_integer( yr_le16toh(field_id_item->type_idx), dex->object, "field_ids[%i].type_idx", i); yr_set_integer( yr_le32toh(field_id_item->name_idx), dex->object, "field_ids[%i].name_idx", i); } if (!fits_in_dex( dex, dex->data + yr_le32toh(dex_header->method_ids_offset), yr_le32toh(dex_header->method_ids_size) * sizeof(method_id_item_t))) return; #ifdef DEBUG_DEX_MODULE printf("[DEX] Parse METHOD ID section\n"); #endif // Get information about the Method ID section for (i = 0; i < yr_le32toh(dex_header->method_ids_size); i++) { method_id_item_t* method_id_item = (method_id_item_t*) (dex->data + yr_le32toh(dex_header->method_ids_offset) + i * sizeof(method_id_item_t)); yr_set_integer( yr_le16toh(method_id_item->class_idx), dex->object, "method_ids[%i].class_idx", i); yr_set_integer( yr_le16toh(method_id_item->proto_idx), dex->object, "method_ids[%i].proto_idx", i); yr_set_integer( yr_le32toh(method_id_item->name_idx), dex->object, "method_ids[%i].name_idx", i); } #ifdef DEBUG_DEX_MODULE printf("[DEX] Parse MAP List ID section\n"); #endif // Get information about the Map List ID section if (yr_le32toh(dex_header->map_offset) != 0 && fits_in_dex( dex, dex->data + yr_le32toh(dex_header->map_offset), sizeof(uint32_t))) { uint32_t* map_list_size = (uint32_t*) (dex->data + yr_le32toh(dex_header->map_offset)); yr_set_integer(yr_le32toh(*map_list_size), dex->object, "map_list.size"); if (!fits_in_dex( dex, dex->data + yr_le32toh(dex_header->map_offset), sizeof(uint32_t) + yr_le32toh(*map_list_size) * sizeof(map_item_t))) return; for (i = 0; i < yr_le32toh(*map_list_size); i++) { map_item_t* map_item = (map_item_t*) (dex->data + yr_le32toh(dex_header->map_offset) + sizeof(uint32_t) + i * sizeof(map_item_t)); if (!struct_fits_in_dex(dex, map_item, map_item_t)) return; yr_set_integer( yr_le16toh(map_item->type), dex->object, "map_list.map_item[%i].type", i); yr_set_integer( yr_le16toh(map_item->unused), dex->object, "map_list.map_item[%i].unused", i); yr_set_integer( yr_le32toh(map_item->size), dex->object, "map_list.map_item[%i].size", i); yr_set_integer( yr_le32toh(map_item->offset), dex->object, "map_list.map_item[%i].offset", i); } } if (!fits_in_dex( dex, dex->data + yr_le32toh(dex_header->class_defs_offset), yr_le32toh(dex_header->class_defs_size) * sizeof(class_id_item_t))) return; #ifdef DEBUG_DEX_MODULE printf("[DEX] Parse CLASS ID section\n"); #endif // Get information about the Class ID section for (i = 0; i < yr_le32toh(dex_header->class_defs_size); i++) { class_id_item_t* class_id_item = (class_id_item_t*) (dex->data + yr_le32toh(dex_header->class_defs_offset) + i * sizeof(class_id_item_t)); #ifdef DEBUG_DEX_MODULE printf( "[DEX] CLASS ID item class_idx:0x%x access_flags:0x%x " "super_class_idx:0x%x interfaces_offset:0x%x source_file_idx:0x%x " "annotations_offset:0x%x class_data_offset:0x%x " "static_values_offset:0x%x\n", yr_le32toh(class_id_item->class_idx), yr_le32toh(class_id_item->access_flags), yr_le32toh(class_id_item->super_class_idx), yr_le32toh(class_id_item->interfaces_offset), yr_le32toh(class_id_item->source_file_idx), yr_le32toh(class_id_item->annotations_offset), yr_le32toh(class_id_item->class_data_offset), yr_le32toh(class_id_item->static_values_offset)); #endif yr_set_integer( yr_le32toh(class_id_item->class_idx), dex->object, "class_defs[%i].class_idx", i); yr_set_integer( yr_le32toh(class_id_item->access_flags), dex->object, "class_defs[%i].access_flags", i); yr_set_integer( yr_le32toh(class_id_item->super_class_idx), dex->object, "class_defs[%i].super_class_idx", i); yr_set_integer( yr_le32toh(class_id_item->interfaces_offset), dex->object, "class_defs[%i].interfaces_offset", i); yr_set_integer( yr_le32toh(class_id_item->source_file_idx), dex->object, "class_defs[%i].source_file_idx", i); yr_set_integer( yr_le32toh(class_id_item->annotations_offset), dex->object, "class_defs[%i].annotations_offset", i); yr_set_integer( yr_le32toh(class_id_item->class_data_offset), dex->object, "class_defs[%i].class_data_offset", i); yr_set_integer( yr_le32toh(class_id_item->static_values_offset), dex->object, "class_defs[%i].static_values_offset", i); if (yr_le32toh(class_id_item->class_data_offset) != 0) { class_data_item_t class_data_item; if (!fits_in_dex( dex, dex->data + yr_le32toh(class_id_item->class_data_offset), 4 * sizeof(uint32_t))) return; uleb128_size = 0; bool error = false; class_data_item.static_fields_size = (uint32_t) read_uleb128_bounded( (dex->data + yr_le32toh(class_id_item->class_data_offset)), data_end, &uleb128_size, &error); if (error) return; class_data_item.instance_fields_size = (uint32_t) read_uleb128_bounded( (dex->data + yr_le32toh(class_id_item->class_data_offset) + uleb128_size), data_end, &uleb128_size, &error); if (error) return; class_data_item.direct_methods_size = (uint32_t) read_uleb128_bounded( (dex->data + yr_le32toh(class_id_item->class_data_offset) + uleb128_size), data_end, &uleb128_size, &error); if (error) return; class_data_item.virtual_methods_size = (uint32_t) read_uleb128_bounded( (dex->data + yr_le32toh(class_id_item->class_data_offset) + uleb128_size), data_end, &uleb128_size, &error); if (error) return; yr_set_integer( class_data_item.static_fields_size, dex->object, "class_data_item[%i].static_fields_size", index_class_data_item); yr_set_integer( class_data_item.instance_fields_size, dex->object, "class_data_item[%i].instance_fields_size", index_class_data_item); yr_set_integer( class_data_item.direct_methods_size, dex->object, "class_data_item[%i].direct_methods_size", index_class_data_item); yr_set_integer( class_data_item.virtual_methods_size, dex->object, "class_data_item[%i].virtual_methods_size", index_class_data_item); #ifdef DEBUG_DEX_MODULE printf("[DEX] CLASS DATA item static fields\n"); #endif uint32_t previous_field_idx = 0; for (j = 0; j < class_data_item.static_fields_size; j++) { new_size = load_encoded_field( dex, yr_le32toh(class_id_item->class_data_offset) + uleb128_size, &previous_field_idx, index_encoded_field, 1, 0); // If the current field isn't parsed the other fields aren't likely to // parse. if (new_size == 0) break; uleb128_size += new_size; index_encoded_field += 1; } #ifdef DEBUG_DEX_MODULE printf("[DEX] CLASS DATA item instance fields\n"); #endif previous_field_idx = 0; for (j = 0; j < class_data_item.instance_fields_size; j++) { new_size = load_encoded_field( dex, yr_le32toh(class_id_item->class_data_offset) + uleb128_size, &previous_field_idx, index_encoded_field, 0, 1); // If the current field isn't parsed the other fields aren't likely to // parse. if (new_size == 0) break; uleb128_size += new_size; index_encoded_field += 1; } #ifdef DEBUG_DEX_MODULE printf("[DEX] CLASS DATA item direct methods\n"); #endif uint32_t previous_method_idx = 0; for (j = 0; j < class_data_item.direct_methods_size; j++) { new_size = load_encoded_method( dex, yr_le32toh(class_id_item->class_data_offset) + uleb128_size, &previous_method_idx, index_encoded_method, 1, 0); // If the current field isn't parsed the other fields aren't likely to // parse. if (new_size == 0) break; uleb128_size += new_size; index_encoded_method += 1; } #ifdef DEBUG_DEX_MODULE printf("[DEX] CLASS DATA item virtual methods\n"); #endif previous_method_idx = 0; for (j = 0; j < class_data_item.virtual_methods_size; j++) { new_size = load_encoded_method( dex, yr_le32toh(class_id_item->class_data_offset) + uleb128_size, &previous_method_idx, index_encoded_method, 0, 1); // If the current field isn't parsed the other fields aren't likely to // parse. if (new_size == 0) break; uleb128_size += new_size; index_encoded_method += 1; } index_class_data_item++; } } yr_set_integer(index_encoded_method, dex->object, "number_of_methods"); yr_set_integer(index_encoded_field, dex->object, "number_of_fields"); } int module_initialize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_finalize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { YR_MEMORY_BLOCK* block; YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; dex_header_t* dex_header; yr_set_sized_string( DEX_FILE_MAGIC_035, 8, module_object, "DEX_FILE_MAGIC_035"); yr_set_sized_string( DEX_FILE_MAGIC_036, 8, module_object, "DEX_FILE_MAGIC_036"); yr_set_sized_string( DEX_FILE_MAGIC_037, 8, module_object, "DEX_FILE_MAGIC_037"); yr_set_sized_string( DEX_FILE_MAGIC_038, 8, module_object, "DEX_FILE_MAGIC_038"); yr_set_sized_string( DEX_FILE_MAGIC_039, 8, module_object, "DEX_FILE_MAGIC_039"); yr_set_integer(0x12345678, module_object, "ENDIAN_CONSTANT"); yr_set_integer(0x78563412, module_object, "REVERSE_ENDIAN_CONSTANT"); yr_set_integer(0xffffffff, module_object, "NO_INDEX"); yr_set_integer(0x1, module_object, "ACC_PUBLIC"); yr_set_integer(0x2, module_object, "ACC_PRIVATE"); yr_set_integer(0x4, module_object, "ACC_PROTECTED"); yr_set_integer(0x8, module_object, "ACC_STATIC"); yr_set_integer(0x10, module_object, "ACC_FINAL"); yr_set_integer(0x20, module_object, "ACC_SYNCHRONIZED"); yr_set_integer(0x40, module_object, "ACC_VOLATILE"); yr_set_integer(0x40, module_object, "ACC_BRIDGE"); yr_set_integer(0x80, module_object, "ACC_TRANSIENT"); yr_set_integer(0x80, module_object, "ACC_VARARGS"); yr_set_integer(0x100, module_object, "ACC_NATIVE"); yr_set_integer(0x200, module_object, "ACC_INTERFACE"); yr_set_integer(0x400, module_object, "ACC_ABSTRACT"); yr_set_integer(0x800, module_object, "ACC_STRICT"); yr_set_integer(0x1000, module_object, "ACC_SYNTHETIC"); yr_set_integer(0x2000, module_object, "ACC_ANNOTATION"); yr_set_integer(0x4000, module_object, "ACC_ENUM"); yr_set_integer(0x10000, module_object, "ACC_CONSTRUCTOR"); yr_set_integer(0x20000, module_object, "ACC_DECLARED_SYNCHRONIZED"); yr_set_integer(0x0000, module_object, "TYPE_HEADER_ITEM"); yr_set_integer(0x0001, module_object, "TYPE_STRING_ID_ITEM"); yr_set_integer(0x0002, module_object, "TYPE_TYPE_ID_ITEM"); yr_set_integer(0x0003, module_object, "TYPE_PROTO_ID_ITEM"); yr_set_integer(0x0004, module_object, "TYPE_FIELD_ID_ITEM"); yr_set_integer(0x0005, module_object, "TYPE_METHOD_ID_ITEM"); yr_set_integer(0x0006, module_object, "TYPE_CLASS_DEF_ITEM"); yr_set_integer(0x0007, module_object, "TYPE_CALL_SITE_ID_ITEM"); yr_set_integer(0x0008, module_object, "TYPE_METHOD_HANDLE_ITEM"); yr_set_integer(0x1000, module_object, "TYPE_MAP_LIST"); yr_set_integer(0x1001, module_object, "TYPE_TYPE_LIST"); yr_set_integer(0x1002, module_object, "TYPE_ANNOTATION_SET_REF_LIST"); yr_set_integer(0x1003, module_object, "TYPE_ANNOTATION_SET_ITEM"); yr_set_integer(0x2000, module_object, "TYPE_CLASS_DATA_ITEM"); yr_set_integer(0x2001, module_object, "TYPE_CODE_ITEM"); yr_set_integer(0x2002, module_object, "TYPE_STRING_DATA_ITEM"); yr_set_integer(0x2003, module_object, "TYPE_DEBUG_INFO_ITEM"); yr_set_integer(0x2004, module_object, "TYPE_ANNOTATION_ITEM"); yr_set_integer(0x2005, module_object, "TYPE_ENCODED_ARRAY_ITEM"); yr_set_integer(0x2006, module_object, "TYPE_ANNOTATIONS_DIRECTORY_ITEM"); foreach_memory_block(iterator, block) { const uint8_t* block_data = yr_fetch_block_data(block); if (block_data == NULL) continue; dex_header = dex_get_header(block_data, block->size); if (dex_header != NULL) { DEX* dex = (DEX*) yr_malloc(sizeof(DEX)); if (dex == NULL) return ERROR_INSUFFICIENT_MEMORY; dex->data = block_data; dex->data_size = block->size; dex->object = module_object; dex->header = dex_header; module_object->data = dex; dex_parse(dex, block->base); break; } } return ERROR_SUCCESS; } int module_unload(YR_OBJECT* module_object) { DEX* dex = (DEX*) module_object->data; if (dex == NULL) return ERROR_SUCCESS; yr_free(dex); return ERROR_SUCCESS; } #undef MODULE_NAME yara-4.5.3/libyara/modules/dotnet/000077500000000000000000000000001501365277300170605ustar00rootroot00000000000000yara-4.5.3/libyara/modules/dotnet/dotnet.c000066400000000000000000003000261501365277300205220ustar00rootroot00000000000000/* Copyright (c) 2015. The YARA Authors. All Rights Reserved. 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MODULE_NAME dotnet static uint32_t max_rows(int count, ...) { va_list ap; uint32_t biggest; uint32_t x; if (count == 0) return 0; va_start(ap, count); biggest = va_arg(ap, uint32_t); for (int i = 1; i < count; i++) { x = va_arg(ap, uint32_t); biggest = (x > biggest) ? x : biggest; } va_end(ap); return biggest; } static uint32_t read_u32(const uint8_t** data) { uint32_t result = yr_le32toh(yr_unaligned_u32(*data)); *data += sizeof(uint32_t); return result; } static uint16_t read_u16(const uint8_t** data) { uint16_t result = yr_le16toh(yr_unaligned_u16(*data)); *data += sizeof(uint16_t); return result; } static uint8_t read_u8(const uint8_t** data) { uint8_t result = **data; *data += sizeof(uint8_t); return result; } static uint32_t read_index(const uint8_t** data, uint8_t len) { if (len == 2) return read_u16(data); else return read_u32(data); } // Returns valid offset within the table or NULL const uint8_t* get_table_offset(const TABLE_INFO* tbl, uint32_t index) { // Indexes to .NET tables are based from 1 if (index < 1 || index > tbl->RowCount) return NULL; return tbl->Offset + tbl->RowSize * (index - 1); } // Given an offset into a #US or #Blob stream, parse the entry at that position. // The offset is relative to the start of the PE file. // if size > 0 then it's valid and readable blob BLOB_PARSE_RESULT dotnet_parse_blob_entry(PE* pe, const uint8_t* offset) { BLOB_PARSE_RESULT result = {.size = 0, .length = 0}; // Blob size is encoded in the first 1, 2 or 4 bytes of the blob. // // If the high bit is not set the length is encoded in one byte. // // If the high 2 bits are 10 (base 2) then the length is encoded in // the rest of the bits and the next byte. // // If the high 3 bits are 110 (base 2) then the length is encoded // in the rest of the bits and the next 3 bytes. // // See ECMA-335 II.24.2.4 for details. // Make sure we have at least one byte. if (!fits_in_pe(pe, offset, 1)) return result; if ((*offset & 0x80) == 0x00) { result.length = (uint32_t) (*offset); result.size = 1; } else if ((*offset & 0xC0) == 0x80) { // Make sure we have one more byte. if (!fits_in_pe(pe, offset, 2)) return result; // Shift remaining 6 bits left by 8 and OR in the remaining byte. result.length = ((*offset & 0x3F) << 8) | *(offset + 1); result.size = 2; } else if (offset + 4 < pe->data + pe->data_size && (*offset & 0xE0) == 0xC0) { // Make sure we have 3 more bytes. if (!fits_in_pe(pe, offset, 4)) return result; result.length = ((*offset & 0x1F) << 24) | (*(offset + 1) << 16) | (*(offset + 2) << 8) | *(offset + 3); result.size = 4; } else { // Return a 0 size as an error. return result; } // Check if the length is actually readable if (!fits_in_pe(pe, offset, result.size + result.length)) { result.size = 0; return result; } return result; } char* pe_get_dotnet_string( PE* pe, const uint8_t* heap_offset, uint32_t heap_size, uint32_t string_index) { size_t remaining; char* start; char* eos; // Start of string must be within boundary if (!(heap_offset + string_index >= pe->data && heap_offset + string_index < pe->data + pe->data_size && string_index < heap_size)) return NULL; // Calculate how much until end of boundary, don't scan past that. remaining = (pe->data + pe->data_size) - (heap_offset + string_index); // Search for a NULL terminator from start of string, up to remaining. start = (char*) (heap_offset + string_index); eos = (char*) memmem((void*) start, remaining, "\0", 1); // If no NULL terminator was found or the string is too large, return NULL. if (eos == NULL || eos - start > 1024) return NULL; return start; } static bool is_nested(uint32_t flags) { // ECMA 335 II.22.37 // Whether a type is nested can be determined by the value of its // Flags.Visibility sub-field – it shall be one of the set // { NestedPublic, NestedPrivate, NestedFamily, NestedAssembly, // NestedFamANDAssem, NestedFamORAssem } switch (flags & TYPE_ATTR_VISIBILITY_MASK) { case TYPE_ATTR_NESTED_PRIVATE: case TYPE_ATTR_NESTED_PUBLIC: case TYPE_ATTR_NESTED_FAMILY: case TYPE_ATTR_NESTED_ASSEMBLY: case TYPE_ATTR_NESTED_FAM_AND_ASSEM: case TYPE_ATTR_NESTED_FAM_OR_ASSEM: return true; default: return false; } } // ECMA 335 II.23.1.15 Flags for types [TypeAttribute] static const char* get_type_visibility(uint32_t flags) { switch (flags & TYPE_ATTR_VISIBILITY_MASK) { case TYPE_ATTR_NESTED_PRIVATE: return "private"; case TYPE_ATTR_PUBLIC: case TYPE_ATTR_NESTED_PUBLIC: return "public"; case TYPE_ATTR_NESTED_FAMILY: return "protected"; case TYPE_ATTR_NOT_PUBLIC: case TYPE_ATTR_NESTED_ASSEMBLY: return "internal"; case TYPE_ATTR_NESTED_FAM_AND_ASSEM: return "private protected"; case TYPE_ATTR_NESTED_FAM_OR_ASSEM: return "protected internal"; default: return "private"; } } // ECMA 335 II.23.1.10 Flags for methods [MethodAttributes] static const char* get_method_visibility(uint32_t flags) { switch (flags & METHOD_ATTR_ACCESS_MASK) { case METHOD_ATTR_PRIVATE: return "private"; case METHOD_ATTR_FAM_AND_ASSEM: return "private protected"; case METHOD_ATTR_ASSEM: return "internal"; case METHOD_ATTR_FAMILY: return "protected"; case METHOD_ATTR_FAM_OR_ASSEM: return "protected internal"; case METHOD_ATTR_PUBLIC: return "public"; default: return "private"; } } // ECMA 335 II.23.1.15 Flags for types [TypeAttribute] static const char* get_typedef_type(uint32_t flags) { switch (flags & TYPE_ATTR_CLASS_SEMANTIC_MASK) { case TYPE_ATTR_CLASS: return "class"; case TYPE_ATTR_INTERFACE: return "interface"; default: return NULL; } } // returns allocated string ., must be freed static char* create_full_name(const char* name, const char* namespace) { if (!name || !strlen(name)) return namespace ? yr_strdup(namespace) : NULL; // No namespace -> return name only if (!namespace || !strlen(namespace)) { // fix generic names char* name_copy = yr_strdup(name); char* end = strchr(name_copy, '`'); if (end) *end = 0; return name_copy; } size_t name_len = strlen(name); size_t namespace_len = strlen(namespace); // . char* full_name = yr_malloc(namespace_len + 1 + name_len + 1); memcpy(full_name, namespace, namespace_len); full_name[namespace_len] = '.'; memcpy(full_name + namespace_len + 1, name, name_len + 1); // fix generic names char* end = strchr(full_name, '`'); if (end) *end = 0; return full_name; } static bool read_typedef( const CLASS_CONTEXT* ctx, const uint8_t* data, TYPEDEF_ROW* result) { uint32_t row_size = ctx->tables->typedef_.RowSize; if (fits_in_pe(ctx->pe, data, row_size)) { uint8_t ext_size = 2; uint32_t row_count = max_rows( 3, ctx->tables->typedef_.RowCount, ctx->tables->typeref.RowCount, ctx->tables->typespec.RowCount); if (row_count > (0xFFFF >> 0x02)) ext_size = 4; result->Flags = read_u32(&data); result->Name = read_index(&data, ctx->index_sizes->string); result->Namespace = read_index(&data, ctx->index_sizes->string); result->Extends = read_index(&data, ext_size); result->Field = read_index(&data, ctx->index_sizes->field); result->Method = read_index(&data, ctx->index_sizes->methoddef); return true; } return false; } static bool read_typeref( const CLASS_CONTEXT* ctx, const uint8_t* data, TYPEREF_ROW* result) { uint32_t row_size = ctx->tables->typeref.RowSize; if (fits_in_pe(ctx->pe, data, row_size)) { uint8_t res_size = 2; uint32_t row_count = max_rows( 4, ctx->tables->module.RowCount, ctx->tables->moduleref.RowCount, ctx->tables->assemblyref.RowCount, ctx->tables->typeref.RowCount); if (row_count > (0xFFFF >> 0x02)) res_size = 4; result->ResolutionScope = read_index(&data, res_size); result->Name = read_index(&data, ctx->index_sizes->string); result->Namespace = read_index(&data, ctx->index_sizes->string); return true; } return false; } static bool read_interfaceimpl( const CLASS_CONTEXT* ctx, const uint8_t* data, INTERFACEIMPL_ROW* result) { uint32_t row_size = ctx->tables->intefaceimpl.RowSize; if (fits_in_pe(ctx->pe, data, row_size)) { uint32_t interface_size = 2; uint32_t row_count = max_rows( 3, ctx->tables->typedef_.RowCount, ctx->tables->typeref.RowCount, ctx->tables->typespec.RowCount); if (row_count > (0xFFFF >> 0x02)) interface_size = 4; result->Class = read_index(&data, ctx->index_sizes->typedef_); result->Interface = read_index(&data, interface_size); return true; } return false; } static bool read_methoddef( const CLASS_CONTEXT* ctx, const uint8_t* data, METHODDEF_ROW* result) { uint32_t row_size = ctx->tables->methoddef.RowSize; if (fits_in_pe(ctx->pe, data, row_size)) { result->Rva = read_u32(&data); result->ImplFlags = read_u16(&data); result->Flags = read_u16(&data); result->Name = read_index(&data, ctx->index_sizes->string); result->Signature = read_index(&data, ctx->index_sizes->blob); result->ParamList = read_index(&data, ctx->index_sizes->param); return true; } return false; } static bool read_param( const CLASS_CONTEXT* ctx, const uint8_t* data, PARAM_ROW* result) { uint32_t row_size = ctx->tables->param.RowSize; if (fits_in_pe(ctx->pe, data, row_size)) { result->Flags = read_u16(&data); result->Sequence = read_u16(&data); result->Name = read_index(&data, ctx->index_sizes->string); return true; } return false; } static bool read_genericparam( const CLASS_CONTEXT* ctx, const uint8_t* data, GENERICPARAM_ROW* result) { uint32_t row_size = ctx->tables->genericparam.RowSize; if (fits_in_pe(ctx->pe, data, row_size)) { uint32_t owner_idx_size = 2; uint32_t row_count = max_rows( 2, ctx->tables->typedef_.RowCount, ctx->tables->methoddef.RowCount); if (row_count > (0xFFFF >> 0x01)) owner_idx_size = 4; result->Number = read_u16(&data); result->Flags = read_u16(&data); result->Owner = read_index(&data, owner_idx_size); result->Name = read_index(&data, ctx->index_sizes->string); return true; } return false; } static bool read_typespec( const CLASS_CONTEXT* ctx, const uint8_t* data, TYPESPEC_ROW* result) { uint32_t row_size = ctx->tables->typespec.RowSize; if (fits_in_pe(ctx->pe, data, row_size)) { result->Signature = read_index(&data, ctx->index_sizes->blob); return true; } return false; } static bool read_nestedclass( const CLASS_CONTEXT* ctx, const uint8_t* data, NESTEDCLASS_ROW* result) { uint32_t row_size = ctx->tables->nestedclass.RowSize; if (fits_in_pe(ctx->pe, data, row_size)) { result->NestedClass = read_index(&data, ctx->index_sizes->typedef_); result->EnclosingClass = read_index(&data, ctx->index_sizes->typedef_); return true; } return false; } // ECMA-335 II.23.2 blob heap uses variable length encoding of integers static uint32_t read_blob_unsigned(const uint8_t** data, uint32_t* len) { if (*len < 1) return 0; // first byte is enough to decode the length // without worrying about endiannity // Compressed integers use big-endian order uint8_t first_byte = *(*data); // If the value lies between 0 (0x00) and 127 (0x7F), inclusive, encode as a // one-byte integer (bit 7 is clear, value held in bits 6 through 0) if (!(first_byte & 0x80)) { *data += sizeof(uint8_t); *len -= sizeof(uint8_t); return first_byte; } if (*len < 2) return 0; // If the value lies between 2^8 (0x80) and 2^14 – 1 (0x3FFF), inclusive, // encode as a 2-byte integer with bit 15 set, bit 14 clear (value held in // bits 13 through 0) if ((first_byte & 0xC0) == 0x80) { uint32_t result = yr_be16toh(yr_unaligned_u16(*data)); *data += sizeof(uint16_t); *len -= sizeof(uint16_t); // value is in lower 14 bits return result & 0x3FFF; } if (*len < 4) return 0; // Otherwise, encode as a 4-byte integer, with bit 31 set, bit 30 set, // bit 29 clear (value held in bits 28 through 0) if ((first_byte & 0xE0) == 0xC0) { uint32_t result = yr_be32toh(yr_unaligned_u32(*data)); *data += sizeof(uint32_t); *len -= sizeof(uint32_t); // Uses last 29 bits for the result return result & 0x1FFFFFFF; } return 0; } // ECMA-335 II.23.2 blob heap uses variable length encoding of integers // Probably wouldn't work on non 2's complement arches? static int32_t read_blob_signed(const uint8_t** data, uint32_t* len) { // Compressed integers use big-endian order! if (*len < 1) return 0; // first byte is enough to decode the length // without worrying about endiannity int8_t first_byte = *(*data); // Encode as a one-byte integer, bit 7 clear, rotated value in bits 6 // through 0, giving 0x01 (-2^6) to 0x7E (2^6-1). if (!(first_byte & 0x80)) { int8_t tmp = first_byte >> 1; // sign extension in case of negative number if (first_byte & 0x1) tmp |= 0xC0; *data += sizeof(uint8_t); *len -= sizeof(uint8_t); return (int32_t) tmp; } if (*len < 2) return 0; // Encode as a two-byte integer: bit 15 set, bit 14 clear, rotated value // in bits 13 through 0, giving 0x8001 (-2^13) to 0xBFFE (2^13-1). if ((first_byte & 0xC0) == 0x80) { uint16_t tmp1 = yr_be16toh(yr_unaligned_u16(*data)); // shift and leave top 2 bits clear int16_t tmp2 = (tmp1 >> 1) & 0x3FFF; // sign extension in case of negative number if (tmp1 & 0x1) tmp2 |= 0xE000; *data += sizeof(uint16_t); *len -= sizeof(uint16_t); return (int32_t) tmp2; } if (*len < 4) return 0; // Encode as a four-byte integer: bit 31 set, 30 set, bit 29 clear, // rotated value in bits 28 through 0, giving 0xC0000001 (-2^28) to // 0xDFFFFFFE (2^28-1). if ((first_byte & 0xE0) == 0xC0) { uint32_t tmp1 = yr_be32toh(yr_unaligned_u32(*data)); // shift and leave top 3 bits clear int32_t tmp2 = (tmp1 >> 1) & 0x1FFFFFFF; // sign extension in case of negative number if (tmp1 & 0x1) tmp2 |= 0xF0000000; *data += sizeof(uint32_t); *len -= sizeof(uint32_t); return (int32_t) tmp2; } return 0; } // Forward declarations static char* parse_signature_type( const CLASS_CONTEXT* ctx, const uint8_t** data, uint32_t* len, GENERIC_PARAMETERS* class_gen_params, GENERIC_PARAMETERS* method_gen_params, uint32_t depth); static char* parse_enclosing_types( const CLASS_CONTEXT* ctx, uint32_t nested_idx, uint32_t depth); static char* get_type_def_or_ref_fullname( const CLASS_CONTEXT* ctx, uint32_t coded_index, GENERIC_PARAMETERS* class_gen_params, GENERIC_PARAMETERS* method_gen_params, uint32_t depth) // against loops { // first 2 bits define table, index starts with third bit uint32_t index = coded_index >> 2; if (!index) return NULL; const uint8_t* str_heap = ctx->str_heap; uint32_t str_size = ctx->str_size; uint8_t table = coded_index & 0x3; if (table == 0) // TypeDef { const uint8_t* data = get_table_offset(&ctx->tables->typedef_, index); if (!data) return NULL; TYPEDEF_ROW def_row; bool result = read_typedef(ctx, data, &def_row); if (result) { const char* name = pe_get_dotnet_string( ctx->pe, str_heap, str_size, def_row.Name); const char* namespace = pe_get_dotnet_string( ctx->pe, str_heap, str_size, def_row.Namespace); char* result = NULL; // Type might be nested, try to find correct namespace if (is_nested(def_row.Flags)) { char* nested_namespace = parse_enclosing_types(ctx, index, 1); char* tmp = create_full_name(namespace, nested_namespace); result = create_full_name(name, tmp); yr_free(nested_namespace); yr_free(tmp); } else result = create_full_name(name, namespace); return result; } } else if (table == 1) // TypeRef { const uint8_t* data = get_table_offset(&ctx->tables->typeref, index); if (!data) return NULL; TYPEREF_ROW ref_row; bool result = read_typeref(ctx, data, &ref_row); if (result) { const char* name = pe_get_dotnet_string( ctx->pe, str_heap, str_size, ref_row.Name); const char* namespace = pe_get_dotnet_string( ctx->pe, str_heap, str_size, ref_row.Namespace); return create_full_name(name, namespace); } } else if (table == 2) // TypeSpec { const uint8_t* data = get_table_offset(&ctx->tables->typespec, index); if (!data) return NULL; TYPESPEC_ROW spec_row; bool result = read_typespec(ctx, data, &spec_row); if (result) { const uint8_t* sig_data = ctx->blob_heap + spec_row.Signature; // Read the blob entry with the data BLOB_PARSE_RESULT blob_res = dotnet_parse_blob_entry(ctx->pe, sig_data); sig_data += blob_res.size; uint32_t sig_len = blob_res.length; // Valid blob if (blob_res.size) return parse_signature_type( ctx, &sig_data, &sig_len, class_gen_params, NULL, depth); } } return NULL; } static char* parse_signature_type( const CLASS_CONTEXT* ctx, const uint8_t** data, uint32_t* len, GENERIC_PARAMETERS* class_gen_params, GENERIC_PARAMETERS* method_gen_params, uint32_t depth // against loops ) { // If at least first type fits and we are not too nested if (*len < 1 || !fits_in_pe(ctx->pe, *data, 1) || depth > MAX_TYPE_DEPTH) return NULL; bool class = false; uint32_t coded_index, index; char* tmp = NULL; char* ret_type = NULL; uint8_t type = read_u8(data); *len -= 1; switch (type) { case TYPE_VOID: ret_type = "void"; break; case TYPE_BOOL: ret_type = "bool"; break; case TYPE_CHAR: ret_type = "char"; break; case TYPE_I1: ret_type = "sbyte"; break; case TYPE_U1: ret_type = "byte"; break; case TYPE_I2: ret_type = "short"; break; case TYPE_U2: ret_type = "ushort"; break; case TYPE_I4: ret_type = "int"; break; case TYPE_U4: ret_type = "uint"; break; case TYPE_I8: ret_type = "long"; break; case TYPE_U8: ret_type = "ulong"; break; case TYPE_R4: ret_type = "float"; break; case TYPE_R8: ret_type = "double"; break; case TYPE_STRING: ret_type = "string"; break; case TYPE_TYPEDREF: ret_type = "TypedReference"; break; case TYPE_I: ret_type = "IntPtr"; break; case TYPE_U: ret_type = "UIntPtr"; break; case TYPE_PTR: // Ptr followed by type tmp = parse_signature_type( ctx, data, len, class_gen_params, method_gen_params, depth + 1); if (tmp) { SIMPLE_STR* ss = sstr_new(NULL); if (!ss) { yr_free(tmp); break; } bool res = sstr_appendf(ss, "Ptr<%s>", tmp); if (res) ret_type = sstr_move(ss); yr_free(tmp); sstr_free(ss); return ret_type; } break; case TYPE_BYREF: // ByRef followed by type tmp = parse_signature_type( ctx, data, len, class_gen_params, method_gen_params, depth + 1); if (tmp) { SIMPLE_STR* ss = sstr_new(NULL); if (!ss) { yr_free(tmp); break; } bool res = sstr_appendf(ss, "ref %s", tmp); if (res) ret_type = sstr_move(ss); yr_free(tmp); sstr_free(ss); return ret_type; } break; case TYPE_VALUETYPE: // ValueType case TYPE_CLASS: // Class // followed by TypeDefOrRefOrSpecEncoded index coded_index = read_blob_unsigned(data, len); return get_type_def_or_ref_fullname( ctx, coded_index, class_gen_params, method_gen_params, depth + 1); break; case TYPE_VAR: // Generic class var case TYPE_MVAR: // Generic method var index = read_blob_unsigned(data, len); class = type == TYPE_VAR; // return class generic var or method generic var if (class && class_gen_params && index < class_gen_params->len) ret_type = class_gen_params->names[index]; else if (!class && method_gen_params && index < method_gen_params->len) ret_type = method_gen_params->names[index]; break; case TYPE_ARRAY: { // Array -> Type -> Rank -> NumSizes -> Size -> NumLobound -> LoBound char* tmp = parse_signature_type( ctx, data, len, class_gen_params, method_gen_params, depth + 1); if (!tmp) break; int32_t* sizes = NULL; int32_t* lo_bounds = NULL; // Read number of dimensions uint32_t rank = read_blob_unsigned(data, len); if (!rank || rank > MAX_ARRAY_RANK) goto cleanup; // Read number of specified sizes uint32_t num_sizes = read_blob_unsigned(data, len); if (num_sizes > rank) goto cleanup; sizes = yr_malloc(sizeof(int64_t) * num_sizes); if (!sizes) goto cleanup; for (uint32_t i = 0; i < num_sizes; ++i) { sizes[i] = (int64_t) read_blob_unsigned(data, len); } // Read number of specified lower bounds uint32_t num_lowbounds = read_blob_unsigned(data, len); lo_bounds = yr_malloc(sizeof(int32_t) * num_lowbounds); if (!lo_bounds || num_lowbounds > rank) goto cleanup; for (uint32_t i = 0; i < num_lowbounds; ++i) { lo_bounds[i] = read_blob_signed(data, len); // Adjust higher bound according to lower bound if (num_sizes > i && lo_bounds[i] != 0) sizes[i] += lo_bounds[i] - 1; } // Build the resulting array type SIMPLE_STR* ss = sstr_new(NULL); if (!ss) goto cleanup; sstr_appendf(ss, "%s[", tmp); for (uint32_t i = 0; i < rank; ++i) { if (num_sizes > i || num_lowbounds > i) { if (num_lowbounds > i && lo_bounds[i] != 0) sstr_appendf(ss, "%d...", lo_bounds[i]); if (num_sizes > i) sstr_appendf(ss, "%d", sizes[i]); } if (i + 1 != rank) sstr_appendf(ss, ","); } bool res = sstr_appendf(ss, "]"); if (res) ret_type = sstr_move(ss); yr_free(sizes); yr_free(lo_bounds); yr_free(tmp); sstr_free(ss); return ret_type; cleanup: yr_free(sizes); yr_free(lo_bounds); yr_free(tmp); } break; case TYPE_GENERICINST: { tmp = parse_signature_type( ctx, data, len, class_gen_params, method_gen_params, depth + 1); if (!tmp) break; uint32_t gen_count = read_blob_unsigned(data, len); // Sanity check for corrupted files if (gen_count > MAX_GEN_PARAM_COUNT) { yr_free(tmp); break; } SIMPLE_STR* ss = sstr_new(NULL); if (!ss) { yr_free(tmp); break; } sstr_appendf(ss, "%s<", tmp); yr_free(tmp); for (int i = 0; i < gen_count; i++) { char* param_type = parse_signature_type( ctx, data, len, class_gen_params, method_gen_params, depth + 1); if (param_type != NULL) { if (i > 0) sstr_appendf(ss, ","); sstr_appendf(ss, "%s", param_type); yr_free(param_type); } } bool res = sstr_appendf(ss, ">"); if (res) ret_type = sstr_move(ss); sstr_free(ss); return ret_type; } break; case TYPE_FNPTR: if (*len > 0) { // Flags -> ParamCount -> RetType -> Param -> Sentinel ->Param // Skip flags (*data)++; (*len)--; uint32_t param_count = read_blob_unsigned(data, len); // Sanity check for corrupted files if (param_count > MAX_PARAM_COUNT) { yr_free(tmp); break; } tmp = parse_signature_type( ctx, data, len, class_gen_params, method_gen_params, depth + 1); if (!tmp) break; SIMPLE_STR* ss = sstr_new(NULL); if (!ss) { yr_free(tmp); break; } sstr_appendf(ss, "FnPtr<%s(", tmp); yr_free(tmp); for (int i = 0; i < param_count; i++) { char* param_type = parse_signature_type( ctx, data, len, class_gen_params, method_gen_params, depth + 1); if (param_type != NULL) { if (i > 0) sstr_appendf(ss, ", "); sstr_appendf(ss, "%s", param_type); yr_free(param_type); } } if (sstr_appendf(ss, ")>")) ret_type = sstr_move(ss); sstr_free(ss); return ret_type; } break; case TYPE_OBJECT: ret_type = "object"; break; case TYPE_SZARRAY: // Single dimensional array followed by type tmp = parse_signature_type( ctx, data, len, class_gen_params, method_gen_params, depth + 1); if (tmp) { SIMPLE_STR* ss = sstr_newf("%s[]", tmp); if (ss) ret_type = sstr_move(ss); yr_free(tmp); sstr_free(ss); return ret_type; } break; case TYPE_CMOD_REQD: // Req modifier case TYPE_CMOD_OPT: // Opt modifier { // What is point of these // Right now ignore them... read_blob_unsigned(data, len); return parse_signature_type( ctx, data, len, class_gen_params, method_gen_params, depth + 1); } break; default: break; } if (ret_type) return yr_strdup(ret_type); else return NULL; } static void parse_type_parents( const CLASS_CONTEXT* ctx, uint32_t extends, uint32_t type_idx, uint32_t out_idx, // Class idx in output array GENERIC_PARAMETERS* class_gen_params) { // Find the parent class char* parent = get_type_def_or_ref_fullname( ctx, extends, class_gen_params, NULL, 0); uint32_t base_type_idx = 0; if (parent) { yr_set_string( parent, ctx->pe->object, "classes[%i].base_types[%i]", out_idx, base_type_idx++); yr_free(parent); } // linear search for every interface that the class implements for (uint32_t idx = 0; idx < ctx->tables->intefaceimpl.RowCount; ++idx) { const uint8_t* data = get_table_offset(&ctx->tables->intefaceimpl, idx + 1); if (!data) break; INTERFACEIMPL_ROW row = {0}; bool result = read_interfaceimpl(ctx, data, &row); if (!result) continue; // We found the inherited interface if (row.Class == type_idx) { char* inteface = get_type_def_or_ref_fullname( ctx, row.Interface, class_gen_params, NULL, 0); if (inteface) { yr_set_string( inteface, ctx->pe->object, "classes[%i].base_types[%i]", out_idx, base_type_idx++); yr_free(inteface); } } } yr_set_integer( base_type_idx, ctx->pe->object, "classes[%i].number_of_base_types", out_idx); } // Returns true if all parameters were correctly parsed static bool parse_method_params( const CLASS_CONTEXT* ctx, uint32_t param_list, uint32_t method_idx, // used for output uint32_t class_idx, uint32_t param_count, const uint8_t* sig_data, uint32_t sig_len, GENERIC_PARAMETERS* class_gen_params, GENERIC_PARAMETERS* method_gen_params) { if (!param_list) // NULL return true; const uint8_t* str_heap = ctx->str_heap; uint32_t str_size = ctx->str_size; // Array to hold all the possible parameters PARAMETERS* params = yr_calloc(param_count, sizeof(PARAMETERS)); if (params == NULL && param_count > 0) return false; for (uint32_t idx = 0; idx < param_count; ++idx) { const uint8_t* data = get_table_offset( &ctx->tables->param, param_list + idx); char* name = NULL; bool alloc = false; // Flag if name needs freeing if (data) // We need param table mostly just for the param name { PARAM_ROW row = {0}; bool result = read_param(ctx, data, &row); if (!result) { // Cleanup and return for (uint32_t j = 0; j < idx; ++j) { if (params[j].alloc) yr_free(params[j].name); yr_free(params[j].type); } yr_free(params); return false; } name = pe_get_dotnet_string(ctx->pe, str_heap, str_size, row.Name); } else // We can reconstruct their type from the signature // and give them default name { alloc = true; SIMPLE_STR* ss = sstr_newf("P_%lu", idx); if (ss) { name = sstr_move(ss); sstr_free(ss); } } char* type = parse_signature_type( ctx, &sig_data, &sig_len, class_gen_params, method_gen_params, 0); params[idx].alloc = alloc; params[idx].name = name; params[idx].type = type; if (!type) // If any param fails, whole parsing is aborted { for (uint32_t j = 0; j <= idx; ++j) { if (params[j].alloc) yr_free(params[j].name); yr_free(params[j].type); } yr_free(params); return false; } } // If we got all of them correctly, write to output and cleanup YR_OBJECT* out_obj = ctx->pe->object; yr_set_integer( param_count, out_obj, "classes[%i].methods[%i].number_of_parameters", class_idx, method_idx); for (uint32_t i = 0; i < param_count; ++i) { yr_set_string( params[i].name, out_obj, "classes[%i].methods[%i].parameters[%i].name", class_idx, method_idx, i); yr_set_string( params[i].type, out_obj, "classes[%i].methods[%i].parameters[%i].type", class_idx, method_idx, i); if (params[i].alloc) yr_free(params[i].name); yr_free(params[i].type); } yr_free(params); return true; } // Walks GenericParam table, finds all generic params for the MethodDef or // TypeDef entry and allocates buffer with the Generic param names into result static void parse_generic_params( const CLASS_CONTEXT* ctx, bool method, // true means MethodDef, false TypeDef index uint32_t gen_idx, GENERIC_PARAMETERS* result) { const uint8_t* str_heap = ctx->str_heap; uint32_t str_size = ctx->str_size; result->names = NULL; result->len = 0; // Walk the GenericParam table to find GenParameters of the class/method for (uint32_t idx = 0; idx < ctx->tables->genericparam.RowCount; ++idx) { const uint8_t* data = get_table_offset(&ctx->tables->genericparam, idx + 1); if (!data) goto cleanup; GENERICPARAM_ROW row = {0}; bool read_result = read_genericparam(ctx, data, &row); if (!read_result) continue; // TypeOrMethodDef coded index uint8_t table = row.Owner & 0x1; // 0 == TypeDef 1 == MethodDef // Check if it's generic param of the type we want if (table == method && (row.Owner >> 1) == gen_idx) { char* name = pe_get_dotnet_string(ctx->pe, str_heap, str_size, row.Name); // name must be valid string if (!name || !*name) // ERROR goto cleanup; result->len += 1; char** tmp = yr_realloc(result->names, result->len * sizeof(char*)); if (!tmp) goto cleanup; // Update the collection result->names = tmp; result->names[result->len - 1] = name; } } return; cleanup: yr_free(result->names); result->names = NULL; result->len = 0; } static void parse_methods( const CLASS_CONTEXT* ctx, uint32_t methodlist, uint32_t method_count, uint32_t class_idx, // class index in the YARA output GENERIC_PARAMETERS* class_gen_params) { if (!methodlist) return; const uint8_t* str_heap = ctx->str_heap; uint32_t str_size = ctx->str_size; uint32_t out_idx = 0; for (uint32_t idx = 0; idx < method_count; ++idx) { const uint8_t* data = get_table_offset( &ctx->tables->methoddef, methodlist + idx); if (!data) break; METHODDEF_ROW row = {0}; bool result = read_methoddef(ctx, data, &row); if (!result) continue; const char* name = pe_get_dotnet_string( ctx->pe, str_heap, str_size, row.Name); // Ignore invalid/empty names if (!name || !*name) continue; // Try to find generic params for the method GENERIC_PARAMETERS method_gen_params = {0}; parse_generic_params(ctx, true, methodlist + idx, &method_gen_params); // Read the blob entry with signature data const uint8_t* sig_data = ctx->blob_heap + row.Signature; BLOB_PARSE_RESULT blob_res = dotnet_parse_blob_entry(ctx->pe, sig_data); sig_data += blob_res.size; uint32_t sig_len = blob_res.length; uint32_t param_count = 0; char* return_type = NULL; // If there is valid blob and at least minimum to parse // (flags, paramCount, retType) parse these basic information if (blob_res.size && sig_len >= 3) { uint8_t flags = read_u8(&sig_data); sig_len -= 1; if (flags & SIG_FLAG_GENERIC) // Generic param count, ignored as we get the // information from generic param table (void) read_blob_unsigned(&sig_data, &sig_len); // Regular param count param_count = read_blob_unsigned(&sig_data, &sig_len); return_type = parse_signature_type( ctx, &sig_data, &sig_len, class_gen_params, &method_gen_params, 0); } else // Error, skip goto clean_next; // Sanity check for corrupted files if (!return_type || param_count > MAX_PARAM_COUNT) goto clean_next; result = parse_method_params( ctx, row.ParamList, out_idx, class_idx, param_count, sig_data, sig_len, class_gen_params, &method_gen_params); if (!result) goto clean_next; const char* visibility = get_method_visibility(row.Flags); uint32_t stat = (row.Flags & METHOD_ATTR_STATIC) != 0; uint32_t final = (row.Flags & METHOD_ATTR_FINAL) != 0; uint32_t virtual = (row.Flags & METHOD_ATTR_VIRTUAL) != 0; uint32_t abstract = (row.Flags & METHOD_ATTR_ABSTRACT) != 0; YR_OBJECT* out_obj = ctx->pe->object; yr_set_string( name, out_obj, "classes[%i].methods[%i].name", class_idx, out_idx); yr_set_string( visibility, out_obj, "classes[%i].methods[%i].visibility", class_idx, out_idx); yr_set_integer( stat, out_obj, "classes[%i].methods[%i].static", class_idx, out_idx); yr_set_integer( virtual, out_obj, "classes[%i].methods[%i].virtual", class_idx, out_idx); yr_set_integer( final, out_obj, "classes[%i].methods[%i].final", class_idx, out_idx); yr_set_integer( abstract, out_obj, "classes[%i].methods[%i].abstract", class_idx, out_idx); yr_set_integer( method_gen_params.len, out_obj, "classes[%i].methods[%i].number_of_generic_parameters", class_idx, out_idx); for (uint32_t i = 0; i < method_gen_params.len; ++i) { yr_set_string( method_gen_params.names[i], ctx->pe->object, "classes[%i].methods[%i].generic_parameters[%i]", class_idx, out_idx, i); } // Unset return type for constructors for FileInfo compatibility if (strcmp(name, ".ctor") != 0 && strcmp(name, ".cctor") != 0) { yr_set_string( return_type, out_obj, "classes[%i].methods[%i].return_type", class_idx, out_idx); } out_idx++; clean_next: yr_free(return_type); yr_free(method_gen_params.names); } yr_set_integer( out_idx, ctx->pe->object, "classes[%i].number_of_methods", class_idx); } // Walks NestedClass table, returns enclosing type fullname or NULL static char* parse_enclosing_types( const CLASS_CONTEXT* ctx, uint32_t nested_idx, uint32_t depth) { if (depth > MAX_NAMESPACE_DEPTH) return NULL; const uint8_t* str_heap = ctx->str_heap; uint32_t str_size = ctx->str_size; for (uint32_t idx = 0; idx < ctx->tables->nestedclass.RowCount; ++idx) { const uint8_t* nested_data = get_table_offset( &ctx->tables->nestedclass, idx + 1); NESTEDCLASS_ROW nested_row = {0}; bool read_result = read_nestedclass(ctx, nested_data, &nested_row); if (!read_result) continue; // We found enclosing class, get the namespace if (nested_row.NestedClass == nested_idx) { const uint8_t* typedef_data = get_table_offset( &ctx->tables->typedef_, nested_row.EnclosingClass); TYPEDEF_ROW typedef_row = {0}; bool result = read_typedef(ctx, typedef_data, &typedef_row); if (!result) break; const char* name = pe_get_dotnet_string( ctx->pe, str_heap, str_size, typedef_row.Name); // Skip the Module pseudo class if (name && strcmp(name, "") == 0) break; const char* namespace = pe_get_dotnet_string( ctx->pe, str_heap, str_size, typedef_row.Namespace); // Type might be further nested, try to find correct namespace, // check for self-reference if (is_nested(typedef_row.Flags) && nested_row.EnclosingClass != nested_row.NestedClass) { char* nested_namespace = parse_enclosing_types( ctx, nested_row.EnclosingClass, depth + 1); char* tmp = create_full_name(namespace, nested_namespace); char* fullname = create_full_name(name, tmp); yr_free(nested_namespace); yr_free(tmp); return fullname; } return create_full_name(name, namespace); } } return NULL; } // Parses and reconstructs user defined types with their methods and base types static void parse_user_types(const CLASS_CONTEXT* ctx) { const uint8_t* str_heap = ctx->str_heap; uint32_t str_size = ctx->str_size; // Index for output tracking, we can't use // offset as some classes can get skipped uint32_t out_idx = 0; // skip first class as it's module pseudo class -> start at index 1 for (uint32_t idx = 0; idx < ctx->tables->typedef_.RowCount; ++idx) { YR_OBJECT* out_obj = ctx->pe->object; // Tables indexing starts at 1 const uint8_t* data = get_table_offset(&ctx->tables->typedef_, idx + 1); TYPEDEF_ROW row = {0}; bool result = read_typedef(ctx, data, &row); if (!result) continue; const char* name = pe_get_dotnet_string( ctx->pe, str_heap, str_size, row.Name); const char* type = get_typedef_type(row.Flags); // Ignore invalid types and invalid (empty) names if (!name || !*name || !type) continue; // If the type is generic, it will include ` at the end of a name // with number of generic arguments, just use the part before that const char* end = strchr(name, '`'); // If the name will turn out empty, skip it and skip Module pseudo class if (end == name || strcmp(name, "") == 0) continue; if (end) yr_set_sized_string( name, end - name, out_obj, "classes[%i].name", out_idx); else yr_set_string(name, out_obj, "classes[%i].name", out_idx); char* fullname = NULL; char* namespace = pe_get_dotnet_string( ctx->pe, str_heap, str_size, row.Namespace); // Type might be nested, if so -> find correct namespace if (is_nested(row.Flags)) { char* nested_namespace = parse_enclosing_types(ctx, idx + 1, 1); namespace = create_full_name(namespace, nested_namespace); yr_set_string(namespace, out_obj, "classes[%i].namespace", out_idx); fullname = create_full_name(name, namespace); yr_free(nested_namespace); yr_free(namespace); } else { yr_set_string(namespace, out_obj, "classes[%i].namespace", out_idx); fullname = create_full_name(name, namespace); } const char* visibility = get_type_visibility(row.Flags); uint32_t abstract = (row.Flags & TYPE_ATTR_ABSTRACT) != 0; uint32_t sealed = (row.Flags & TYPE_ATTR_SEALED) != 0; yr_set_string(fullname, out_obj, "classes[%i].fullname", out_idx); yr_set_string(visibility, out_obj, "classes[%i].visibility", out_idx); yr_set_string(type, out_obj, "classes[%i].type", out_idx); yr_set_integer(abstract, out_obj, "classes[%i].abstract", out_idx); yr_set_integer(sealed, out_obj, "classes[%i].sealed", out_idx); yr_free(fullname); // Find if type has any Generic parameters GENERIC_PARAMETERS gen_params = {0}; parse_generic_params(ctx, false, idx + 1, &gen_params); yr_set_integer( gen_params.len, out_obj, "classes[%i].number_of_generic_parameters", out_idx); for (uint32_t i = 0; i < gen_params.len; ++i) { yr_set_string( gen_params.names[i], out_obj, "classes[%i].generic_parameters[%i]", out_idx, i); } // Find type and interfaces the type inherits parse_type_parents(ctx, row.Extends, idx + 1, out_idx, &gen_params); // To get the number of methods, we must peek where the MethodList // of the next type is, then there is next.MethodList - this.MethodList // number of methods, or if there is no following type, // the rest of the MethodDef table is used uint32_t method_count = 0; // If there is next method if (idx + 1 < ctx->tables->typedef_.RowCount) { const uint8_t* data = get_table_offset(&ctx->tables->typedef_, idx + 2); TYPEDEF_ROW next_row = {0}; result = read_typedef(ctx, data, &next_row); // overflow check if (result && next_row.Method >= row.Method) method_count = next_row.Method - row.Method; } // overflow check - use the rest of the methods in the table else if (ctx->tables->methoddef.RowCount >= row.Method) { method_count = ctx->tables->methoddef.RowCount + 1 - row.Method; } // Sanity check for corrupted files if (method_count <= MAX_METHOD_COUNT) parse_methods(ctx, row.Method, method_count, out_idx, &gen_params); yr_free(gen_params.names); out_idx++; } yr_set_integer(out_idx, ctx->pe->object, "number_of_classes"); } void dotnet_parse_guid( PE* pe, int64_t metadata_root, PSTREAM_HEADER guid_header) { // GUIDs are 16 bytes each, converted to hex format plus separators and NULL. char guid[37]; int i = 0; const uint8_t* guid_offset = pe->data + metadata_root + yr_le32toh(guid_header->Offset); DWORD guid_size = yr_le32toh(guid_header->Size); // Limit the number of GUIDs to 16. guid_size = yr_min(guid_size, 256); // Parse GUIDs if we have them. GUIDs are 16 bytes each. while (guid_size >= 16 && fits_in_pe(pe, guid_offset, 16)) { sprintf( guid, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", yr_le32toh(*(uint32_t*) guid_offset), yr_le16toh(*(uint16_t*) (guid_offset + 4)), yr_le16toh(*(uint16_t*) (guid_offset + 6)), *(guid_offset + 8), *(guid_offset + 9), *(guid_offset + 10), *(guid_offset + 11), *(guid_offset + 12), *(guid_offset + 13), *(guid_offset + 14), *(guid_offset + 15)); guid[(16 * 2) + 4] = '\0'; yr_set_string(guid, pe->object, "guids[%i]", i); i++; guid_size -= 16; guid_offset += 16; } yr_set_integer(i, pe->object, "number_of_guids"); } void dotnet_parse_us(PE* pe, int64_t metadata_root, PSTREAM_HEADER us_header) { BLOB_PARSE_RESULT blob_result; int i = 0; const uint32_t ush_sz = yr_le32toh(us_header->Size); const uint8_t* offset = pe->data + metadata_root + yr_le32toh(us_header->Offset); const uint8_t* end_of_header = offset + ush_sz; // Make sure the header size is larger than 0 and its end is not past the // end of PE. if (ush_sz == 0 || !fits_in_pe(pe, offset, ush_sz)) return; // The first entry MUST be single NULL byte. if (*offset != 0x00) return; offset++; while (offset < end_of_header) { blob_result = dotnet_parse_blob_entry(pe, offset); if (blob_result.size == 0) break; offset += blob_result.size; // There is an additional terminal byte which is 0x01 under certain // conditions - when any top bit in utf16 top byte is set. // The exact conditions are not relevant to our parsing but are // documented in ECMA-335 II.24.2.4. if (blob_result.length > 0) blob_result.length--; // Avoid empty strings, which usually happen as padding at the end of the // stream. if (blob_result.length > 0 && fits_in_pe(pe, offset, blob_result.length)) { yr_set_sized_string( (char*) offset, blob_result.length, pe->object, "user_strings[%i]", i); offset += blob_result.length; i++; } } yr_set_integer(i, pe->object, "number_of_user_strings"); } STREAMS dotnet_parse_stream_headers( PE* pe, int64_t offset, int64_t metadata_root, DWORD num_streams) { PSTREAM_HEADER stream_header; STREAMS headers; char* start; char* eos; char stream_name[DOTNET_STREAM_NAME_SIZE + 1]; unsigned int i; memset(&headers, '\0', sizeof(STREAMS)); headers.metadata_root = metadata_root; stream_header = (PSTREAM_HEADER) (pe->data + offset); for (i = 0; i < num_streams; i++) { if (!struct_fits_in_pe(pe, stream_header, STREAM_HEADER)) break; start = (char*) stream_header->Name; if (!fits_in_pe(pe, start, DOTNET_STREAM_NAME_SIZE)) break; eos = (char*) memmem((void*) start, DOTNET_STREAM_NAME_SIZE, "\0", 1); if (eos == NULL) break; strncpy(stream_name, stream_header->Name, DOTNET_STREAM_NAME_SIZE); stream_name[DOTNET_STREAM_NAME_SIZE] = '\0'; yr_set_string(stream_name, pe->object, "streams[%i].name", i); // Offset is relative to metadata_root. yr_set_integer( metadata_root + yr_le32toh(stream_header->Offset), pe->object, "streams[%i].offset", i); yr_set_integer( yr_le32toh(stream_header->Size), pe->object, "streams[%i].size", i); // Store necessary bits to parse these later. Not all tables will be // parsed, but are referenced from others. For example, the #Strings // stream is referenced from various tables in the #~ heap. // // #- is not documented but it represents unoptimized metadata stream. It // may contain additional tables such as FieldPtr, ParamPtr, MethodPtr or // PropertyPtr for indirect referencing. We already take into account these // tables and they do not interfere with anything we parse in this module. if ((strncmp(stream_name, "#~", 2) == 0 || strncmp(stream_name, "#-", 2) == 0) && headers.tilde == NULL) headers.tilde = stream_header; else if (strncmp(stream_name, "#GUID", 5) == 0) headers.guid = stream_header; else if (strncmp(stream_name, "#Strings", 8) == 0 && headers.string == NULL) headers.string = stream_header; else if (strncmp(stream_name, "#Blob", 5) == 0 && headers.blob == NULL) headers.blob = stream_header; else if (strncmp(stream_name, "#US", 3) == 0 && headers.us == NULL) headers.us = stream_header; // Stream name is padded to a multiple of 4. stream_header = (PSTREAM_HEADER) ((uint8_t*) stream_header + sizeof(STREAM_HEADER) + strlen(stream_name) + 4 - (strlen(stream_name) % 4)); } yr_set_integer(i, pe->object, "number_of_streams"); return headers; } // This is the second pass through the data for #~. The first pass collects // information on the number of rows for tables which have coded indexes. // This pass uses that information and the index_sizes to parse the tables // of interest. // // Because the indexes can vary in size depending upon the number of rows in // other tables it is impossible to use static sized structures. To deal with // this hardcode the sizes of each table based upon the documentation (for the // static sized portions) and use the variable sizes accordingly. void dotnet_parse_tilde_2( PE* pe, PTILDE_HEADER tilde_header, int64_t resource_base, ROWS rows, INDEX_SIZES index_sizes, PSTREAMS streams) { PMODULE_TABLE module_table; PASSEMBLY_TABLE assembly_table; PASSEMBLYREF_TABLE assemblyref_table; PFIELDRVA_TABLE fieldrva_table; PMANIFESTRESOURCE_TABLE manifestresource_table; PMODULEREF_TABLE moduleref_table; PCUSTOMATTRIBUTE_TABLE customattribute_table; PCONSTANT_TABLE constant_table; DWORD resource_size, implementation; // To save important data for future processing, initialize everything to 0 TABLES tables = {0}; char* name; char typelib[MAX_TYPELIB_SIZE + 1]; unsigned int i; int bit_check; int matched_bits = 0; int64_t metadata_root = streams->metadata_root; int64_t resource_offset, field_offset; uint32_t row_size, row_count, counter, str_heap_size; const uint8_t* string_offset; const uint8_t* blob_offset; uint32_t num_rows = 0; uint32_t valid_rows = 0; uint32_t* row_offset = NULL; uint8_t* table_offset = NULL; uint8_t* row_ptr = NULL; // These are pointers and row sizes for tables of interest to us for special // parsing. For example, we are interested in pulling out any CustomAttributes // that are GUIDs so we need to be able to walk these tables. To find GUID // CustomAttributes you need to walk the CustomAttribute table and look for // any row with a Parent that indexes into the Assembly table and Type indexes // into the MemberRef table. Then you follow the index into the MemberRef // table and check the Class to make sure it indexes into TypeRef table. If it // does you follow that index and make sure the Name is "GuidAttribute". If // all that is valid then you can take the Value from the CustomAttribute // table to find out the index into the Blob stream and parse that. // // Luckily we can abuse the fact that the order of the tables is guaranteed // consistent (though some may not exist, but if they do exist they must exist // in a certain order). The order is defined by their position in the Valid // member of the tilde_header structure. By the time we are parsing the // CustomAttribute table we have already recorded the location of the TypeRef // and MemberRef tables, so we can follow the chain back up from // CustomAttribute through MemberRef to TypeRef. uint8_t* typeref_ptr = NULL; uint8_t* memberref_ptr = NULL; uint32_t typeref_row_size = 0; uint32_t memberref_row_size = 0; uint8_t* typeref_row = NULL; uint8_t* memberref_row = NULL; DWORD type_index; DWORD class_index; BLOB_PARSE_RESULT blob_result; DWORD blob_index; DWORD blob_length; // These are used to determine the size of coded indexes, which are the // dynamically sized columns for some tables. The coded indexes are // documented in ECMA-335 Section II.24.2.6. uint8_t index_size, index_size2; // Number of rows is the number of bits set to 1 in Valid. // Should use this technique: // http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan // Count number of Rows size entries in header to skip over them for (i = 0; i < 64; i++) valid_rows += ((yr_le64toh(tilde_header->Valid) >> i) & 0x01); row_offset = (uint32_t*) (tilde_header + 1); table_offset = (uint8_t*) row_offset; table_offset += sizeof(uint32_t) * valid_rows; // Sometimes files have some sort of padding after, from DnSpy source // it's denoted by EXTRA_DATA 0x40 flag in heapflags // We then need to offset by 4 bytes, otherwise the analysis is wrong // https://github.com/dnSpy/dnSpy/blob/2b6dcfaf602fb8ca6462b8b6237fdfc0c74ad994/dnSpy/dnSpy/Hex/Files/DotNet/TablesHeaderDataImpl.cs // example: 1c2246af11000c3ce6b05ed6ba25060cbb00273c599428b98cf4013bdd82892f if (tilde_header->HeapSizes & HEAP_EXTRA_DATA) table_offset += 4; #define DOTNET_STRING_INDEX(Name) \ index_sizes.string == 2 ? yr_le16toh(Name.Name_Short) \ : yr_le32toh(Name.Name_Long) string_offset = pe->data + metadata_root + yr_le32toh(streams->string->Offset); str_heap_size = yr_le32toh(streams->string->Size); // Now walk again this time parsing out what we care about. for (bit_check = 0; bit_check < 64; bit_check++) { // If the Valid bit is not set for this table, skip it... if (!((yr_le64toh(tilde_header->Valid) >> bit_check) & 0x01)) continue; if (!fits_in_pe(pe, row_offset + matched_bits, sizeof(uint32_t))) return; num_rows = yr_le32toh(*(row_offset + matched_bits)); // Make sure that num_rows has a reasonable value. For example // edc05e49dd3810be67942b983455fd43 sets a large value for number of // rows for the BIT_MODULE section. if (num_rows > 15000) return; // Those tables which exist, but that we don't care about must be // skipped. // // Sadly, given the dynamic sizes of some columns we can not have well // defined structures for all tables and use them accordingly. To deal // with this manually move the table_offset pointer by the appropriate // number of bytes as described in the documentation for each table. // // The table structures are documented in ECMA-335 Section II.22. switch (bit_check) { case BIT_MODULE: module_table = (PMODULE_TABLE) table_offset; if (!struct_fits_in_pe(pe, module_table, MODULE_TABLE)) break; name = pe_get_dotnet_string( pe, string_offset, str_heap_size, DOTNET_STRING_INDEX(module_table->Name)); if (name != NULL) yr_set_string(name, pe->object, "module_name"); row_size = 2 + index_sizes.string + (index_sizes.guid * 3); tables.module.Offset = table_offset; tables.module.RowCount = num_rows; tables.module.RowSize = row_size; table_offset += row_size * num_rows; break; case BIT_TYPEREF: row_count = max_rows( 4, yr_le32toh(rows.module), yr_le32toh(rows.moduleref), yr_le32toh(rows.assemblyref), yr_le32toh(rows.typeref)); if (row_count > (0xFFFF >> 0x02)) index_size = 4; else index_size = 2; row_size = (index_size + (index_sizes.string * 2)); typeref_row_size = row_size; typeref_ptr = table_offset; tables.typeref.Offset = table_offset; tables.typeref.RowCount = num_rows; tables.typeref.RowSize = row_size; table_offset += row_size * num_rows; break; case BIT_TYPEDEF: row_count = max_rows( 3, yr_le32toh(rows.typedef_), yr_le32toh(rows.typeref), yr_le32toh(rows.typespec)); if (row_count > (0xFFFF >> 0x02)) index_size = 4; else index_size = 2; row_size = 4 + (index_sizes.string * 2) + index_size + index_sizes.field + index_sizes.methoddef; tables.typedef_.Offset = table_offset; tables.typedef_.RowCount = num_rows; tables.typedef_.RowSize = row_size; table_offset += row_size * num_rows; break; case BIT_FIELDPTR: // This one is not documented in ECMA-335. table_offset += (index_sizes.field) * num_rows; break; case BIT_FIELD: table_offset += (2 + (index_sizes.string) + index_sizes.blob) * num_rows; break; case BIT_METHODDEFPTR: // This one is not documented in ECMA-335. table_offset += (index_sizes.methoddef) * num_rows; break; case BIT_METHODDEF: row_size = 4 + 2 + 2 + index_sizes.string + index_sizes.blob + index_sizes.param; tables.methoddef.Offset = table_offset; tables.methoddef.RowCount = num_rows; tables.methoddef.RowSize = row_size; table_offset += row_size * num_rows; break; case BIT_PARAM: row_size = 2 + 2 + index_sizes.string; tables.param.Offset = table_offset; tables.param.RowCount = num_rows; tables.param.RowSize = row_size; table_offset += row_size * num_rows; break; case BIT_INTERFACEIMPL: row_count = max_rows( 3, yr_le32toh(rows.typedef_), yr_le32toh(rows.typeref), yr_le32toh(rows.typespec)); if (row_count > (0xFFFF >> 0x02)) index_size = 4; else index_size = 2; row_size = index_sizes.typedef_ + index_size; tables.intefaceimpl.Offset = table_offset; tables.intefaceimpl.RowCount = num_rows; tables.intefaceimpl.RowSize = row_size; table_offset += row_size * num_rows; break; case BIT_MEMBERREF: row_count = max_rows( 4, yr_le32toh(rows.methoddef), yr_le32toh(rows.moduleref), yr_le32toh(rows.typeref), yr_le32toh(rows.typespec)); if (row_count > (0xFFFF >> 0x03)) index_size = 4; else index_size = 2; row_size = (index_size + index_sizes.string + index_sizes.blob); memberref_row_size = row_size; memberref_ptr = table_offset; table_offset += row_size * num_rows; break; case BIT_CONSTANT: row_count = max_rows( 3, yr_le32toh(rows.param), yr_le32toh(rows.field), yr_le32toh(rows.property)); if (row_count > (0xFFFF >> 0x02)) index_size = 4; else index_size = 2; // Using 'i' is insufficent since we may skip certain constants and // it would give an inaccurate count in that case. counter = 0; row_size = (1 + 1 + index_size + index_sizes.blob); row_ptr = table_offset; for (i = 0; i < num_rows; i++) { if (!fits_in_pe(pe, row_ptr, row_size)) break; constant_table = (PCONSTANT_TABLE) row_ptr; // Only look for constants of type string. if (yr_le32toh(constant_table->Type) != TYPE_STRING) { row_ptr += row_size; continue; } // Get the blob offset and pull it out of the blob table. blob_offset = ((uint8_t*) constant_table) + 2 + index_size; if (index_sizes.blob == 4) blob_index = *(DWORD*) blob_offset; else // Cast the value (index into blob table) to a 32bit value. blob_index = (DWORD) (*(WORD*) blob_offset); // Everything checks out. Make sure the index into the blob field // is valid (non-null and within range). blob_offset = pe->data + metadata_root + yr_le32toh(streams->blob->Offset) + blob_index; blob_result = dotnet_parse_blob_entry(pe, blob_offset); if (blob_result.size == 0) { row_ptr += row_size; continue; } blob_length = blob_result.length; blob_offset += blob_result.size; // Quick sanity check to make sure the blob entry is within bounds. if (blob_offset + blob_length >= pe->data + pe->data_size) { row_ptr += row_size; continue; } yr_set_sized_string( (char*) blob_offset, blob_result.length, pe->object, "constants[%i]", counter); counter++; row_ptr += row_size; } yr_set_integer(counter, pe->object, "number_of_constants"); table_offset += row_size * num_rows; break; case BIT_CUSTOMATTRIBUTE: // index_size is size of the parent column. row_count = max_rows( 21, yr_le32toh(rows.methoddef), yr_le32toh(rows.field), yr_le32toh(rows.typeref), yr_le32toh(rows.typedef_), yr_le32toh(rows.param), yr_le32toh(rows.interfaceimpl), yr_le32toh(rows.memberref), yr_le32toh(rows.module), yr_le32toh(rows.property), yr_le32toh(rows.event), yr_le32toh(rows.standalonesig), yr_le32toh(rows.moduleref), yr_le32toh(rows.typespec), yr_le32toh(rows.assembly), yr_le32toh(rows.assemblyref), yr_le32toh(rows.file), yr_le32toh(rows.exportedtype), yr_le32toh(rows.manifestresource), yr_le32toh(rows.genericparam), yr_le32toh(rows.genericparamconstraint), yr_le32toh(rows.methodspec)); if (row_count > (0xFFFF >> 0x05)) index_size = 4; else index_size = 2; // index_size2 is size of the type column. row_count = max_rows( 2, yr_le32toh(rows.methoddef), yr_le32toh(rows.memberref)); if (row_count > (0xFFFF >> 0x03)) index_size2 = 4; else index_size2 = 2; row_size = (index_size + index_size2 + index_sizes.blob); if (typeref_ptr != NULL && memberref_ptr != NULL) { row_ptr = table_offset; for (i = 0; i < num_rows; i++) { if (!fits_in_pe(pe, row_ptr, row_size)) break; // Check the Parent field. customattribute_table = (PCUSTOMATTRIBUTE_TABLE) row_ptr; if (index_size == 4) { // Low 5 bits tell us what this is an index into. Remaining bits // tell us the index value. // Parent must be an index into the Assembly (0x0E) table. if ((*(DWORD*) customattribute_table & 0x1F) != 0x0E) { row_ptr += row_size; continue; } } else { // Low 5 bits tell us what this is an index into. Remaining bits // tell us the index value. // Parent must be an index into the Assembly (0x0E) table. if ((*(WORD*) customattribute_table & 0x1F) != 0x0E) { row_ptr += row_size; continue; } } // Check the Type field. customattribute_table = (PCUSTOMATTRIBUTE_TABLE) (row_ptr + index_size); if (index_size2 == 4) { // Low 3 bits tell us what this is an index into. Remaining bits // tell us the index value. Only values 2 and 3 are defined. // Type must be an index into the MemberRef table. if ((*(DWORD*) customattribute_table & 0x07) != 0x03) { row_ptr += row_size; continue; } type_index = *(DWORD*) customattribute_table >> 3; } else { // Low 3 bits tell us what this is an index into. Remaining bits // tell us the index value. Only values 2 and 3 are defined. // Type must be an index into the MemberRef table. if ((*(WORD*) customattribute_table & 0x07) != 0x03) { row_ptr += row_size; continue; } // Cast the index to a 32bit value. type_index = (DWORD) ((*(WORD*) customattribute_table >> 3)); } if (type_index > 0) type_index--; // Now follow the Type index into the MemberRef table. memberref_row = memberref_ptr + (memberref_row_size * type_index); if (!fits_in_pe(pe, memberref_row, memberref_row_size)) break; if (index_sizes.memberref == 4) { // Low 3 bits tell us what this is an index into. Remaining bits // tell us the index value. Class must be an index into the // TypeRef table. if ((*(DWORD*) memberref_row & 0x07) != 0x01) { row_ptr += row_size; continue; } class_index = *(DWORD*) memberref_row >> 3; } else { // Low 3 bits tell us what this is an index into. Remaining bits // tell us the index value. Class must be an index into the // TypeRef table. if ((*(WORD*) memberref_row & 0x07) != 0x01) { row_ptr += row_size; continue; } // Cast the index to a 32bit value. class_index = (DWORD) (*(WORD*) memberref_row >> 3); } if (class_index > 0) class_index--; // Now follow the Class index into the TypeRef table. typeref_row = typeref_ptr + (typeref_row_size * class_index); if (!fits_in_pe(pe, typeref_row, typeref_row_size)) break; // Skip over the ResolutionScope and check the Name field, // which is an index into the Strings heap. row_count = max_rows( 4, yr_le32toh(rows.module), yr_le32toh(rows.moduleref), yr_le32toh(rows.assemblyref), yr_le32toh(rows.typeref)); if (row_count > (0xFFFF >> 0x02)) typeref_row += 4; else typeref_row += 2; if (index_sizes.string == 4) { name = pe_get_dotnet_string( pe, string_offset, str_heap_size, *(DWORD*) typeref_row); } else { name = pe_get_dotnet_string( pe, string_offset, str_heap_size, *(WORD*) typeref_row); } if (name != NULL && strncmp(name, "GuidAttribute", 13) != 0) { row_ptr += row_size; continue; } // Get the Value field. customattribute_table = (PCUSTOMATTRIBUTE_TABLE) (row_ptr + index_size + index_size2); if (index_sizes.blob == 4) blob_index = *(DWORD*) customattribute_table; else // Cast the value (index into blob table) to a 32bit value. blob_index = (DWORD) (*(WORD*) customattribute_table); // Everything checks out. Make sure the index into the blob field // is valid (non-null and within range). blob_offset = pe->data + metadata_root + yr_le32toh(streams->blob->Offset) + blob_index; // If index into blob is 0 or past the end of the blob stream, skip // it. We don't know the size of the blob entry yet because that is // encoded in the start. if (blob_index == 0x00 || blob_offset >= pe->data + pe->data_size) { row_ptr += row_size; continue; } blob_result = dotnet_parse_blob_entry(pe, blob_offset); if (blob_result.size == 0) { row_ptr += row_size; continue; } blob_length = blob_result.length; blob_offset += blob_result.size; // Quick sanity check to make sure the blob entry is within bounds // and its length is at least 3 (2 bytes for the 16 bits prolog and // 1 byte for the string length) if (blob_length < 3 || blob_offset + blob_length >= pe->data + pe->data_size) { row_ptr += row_size; continue; } // Custom attributes MUST have a 16 bit prolog of 0x0001 if (*(WORD*) blob_offset != 0x0001) { row_ptr += row_size; continue; } // The next byte after the 16 bit prolog is the length of the string. blob_offset += 2; uint8_t str_len = *blob_offset; // Increment blob_offset so that it points to the first byte of the // string. blob_offset += 1; if (blob_offset + str_len > pe->data + pe->data_size) { row_ptr += row_size; continue; } if (*blob_offset == 0xFF || *blob_offset == 0x00) { typelib[0] = '\0'; } else { strncpy(typelib, (char*) blob_offset, str_len); typelib[str_len] = '\0'; } yr_set_string(typelib, pe->object, "typelib"); row_ptr += row_size; } } table_offset += row_size * num_rows; break; case BIT_FIELDMARSHAL: row_count = max_rows(2, yr_le32toh(rows.field), yr_le32toh(rows.param)); if (row_count > (0xFFFF >> 0x01)) index_size = 4; else index_size = 2; table_offset += (index_size + index_sizes.blob) * num_rows; break; case BIT_DECLSECURITY: row_count = max_rows( 3, yr_le32toh(rows.typedef_), yr_le32toh(rows.methoddef), yr_le32toh(rows.assembly)); if (row_count > (0xFFFF >> 0x02)) index_size = 4; else index_size = 2; table_offset += (2 + index_size + index_sizes.blob) * num_rows; break; case BIT_CLASSLAYOUT: table_offset += (2 + 4 + index_sizes.typedef_) * num_rows; break; case BIT_FIELDLAYOUT: table_offset += (4 + index_sizes.field) * num_rows; break; case BIT_STANDALONESIG: table_offset += (index_sizes.blob) * num_rows; break; case BIT_EVENTMAP: table_offset += (index_sizes.typedef_ + index_sizes.event) * num_rows; break; case BIT_EVENTPTR: // This one is not documented in ECMA-335. table_offset += (index_sizes.event) * num_rows; break; case BIT_EVENT: row_count = max_rows( 3, yr_le32toh(rows.typedef_), yr_le32toh(rows.typeref), yr_le32toh(rows.typespec)); if (row_count > (0xFFFF >> 0x02)) index_size = 4; else index_size = 2; table_offset += (2 + index_sizes.string + index_size) * num_rows; break; case BIT_PROPERTYMAP: table_offset += (index_sizes.typedef_ + index_sizes.property) * num_rows; break; case BIT_PROPERTYPTR: // This one is not documented in ECMA-335. table_offset += (index_sizes.property) * num_rows; break; case BIT_PROPERTY: table_offset += (2 + index_sizes.string + index_sizes.blob) * num_rows; break; case BIT_METHODSEMANTICS: row_count = max_rows( 2, yr_le32toh(rows.event), yr_le32toh(rows.property)); if (row_count > (0xFFFF >> 0x01)) index_size = 4; else index_size = 2; table_offset += (2 + index_sizes.methoddef + index_size) * num_rows; break; case BIT_METHODIMPL: row_count = max_rows( 2, yr_le32toh(rows.methoddef), yr_le32toh(rows.memberref)); if (row_count > (0xFFFF >> 0x01)) index_size = 4; else index_size = 2; table_offset += (index_sizes.typedef_ + (index_size * 2)) * num_rows; break; case BIT_MODULEREF: row_ptr = table_offset; // Can't use 'i' here because we only set the string if it is not // NULL. Instead use 'counter'. counter = 0; for (i = 0; i < num_rows; i++) { moduleref_table = (PMODULEREF_TABLE) row_ptr; if (!struct_fits_in_pe(pe, moduleref_table, MODULEREF_TABLE)) break; name = pe_get_dotnet_string( pe, string_offset, str_heap_size, DOTNET_STRING_INDEX(moduleref_table->Name)); if (name != NULL) { yr_set_string(name, pe->object, "modulerefs[%i]", counter); counter++; } row_ptr += index_sizes.string; } yr_set_integer(counter, pe->object, "number_of_modulerefs"); row_size = index_sizes.string; tables.moduleref.Offset = table_offset; tables.moduleref.RowCount = num_rows; tables.moduleref.RowSize = row_size; table_offset += row_size * num_rows; break; case BIT_TYPESPEC: row_size = index_sizes.blob; tables.typespec.Offset = table_offset; tables.typespec.RowCount = num_rows; tables.typespec.RowSize = row_size; table_offset += row_size * num_rows; break; case BIT_IMPLMAP: row_count = max_rows( 2, yr_le32toh(rows.field), yr_le32toh(rows.methoddef)); if (row_count > (0xFFFF >> 0x01)) index_size = 4; else index_size = 2; table_offset += (2 + index_size + index_sizes.string + index_sizes.moduleref) * num_rows; break; case BIT_FIELDRVA: row_size = 4 + index_sizes.field; row_ptr = table_offset; // Can't use 'i' here because we only set the field offset if it is // valid. Instead use 'counter'. counter = 0; for (i = 0; i < num_rows; i++) { fieldrva_table = (PFIELDRVA_TABLE) row_ptr; if (!struct_fits_in_pe(pe, fieldrva_table, FIELDRVA_TABLE)) break; field_offset = pe_rva_to_offset(pe, fieldrva_table->RVA); if (field_offset >= 0) { yr_set_integer( field_offset, pe->object, "field_offsets[%i]", counter); counter++; } row_ptr += row_size; } yr_set_integer(counter, pe->object, "number_of_field_offsets"); table_offset += row_size * num_rows; break; case BIT_ENCLOG: table_offset += (4 + 4) * num_rows; break; case BIT_ENCMAP: table_offset += (4) * num_rows; break; case BIT_ASSEMBLY: row_size = (4 + 2 + 2 + 2 + 2 + 4 + index_sizes.blob + (index_sizes.string * 2)); if (!fits_in_pe(pe, table_offset, row_size)) break; row_ptr = table_offset; assembly_table = (PASSEMBLY_TABLE) table_offset; yr_set_integer( yr_le16toh(assembly_table->MajorVersion), pe->object, "assembly.version.major"); yr_set_integer( yr_le16toh(assembly_table->MinorVersion), pe->object, "assembly.version.minor"); yr_set_integer( yr_le16toh(assembly_table->BuildNumber), pe->object, "assembly.version.build_number"); yr_set_integer( yr_le16toh(assembly_table->RevisionNumber), pe->object, "assembly.version.revision_number"); // Can't use assembly_table here because the PublicKey comes before // Name and is a variable length field. if (index_sizes.string == 4) name = pe_get_dotnet_string( pe, string_offset, str_heap_size, yr_le32toh(*(DWORD*) (row_ptr + 4 + 2 + 2 + 2 + 2 + 4 + index_sizes.blob))); else name = pe_get_dotnet_string( pe, string_offset, str_heap_size, yr_le16toh( *(WORD*) (row_ptr + 4 + 2 + 2 + 2 + 2 + 4 + index_sizes.blob))); if (name != NULL) yr_set_string(name, pe->object, "assembly.name"); // Culture comes after Name. if (index_sizes.string == 4) { name = pe_get_dotnet_string( pe, string_offset, str_heap_size, yr_le32toh(*(DWORD*) (row_ptr + 4 + 2 + 2 + 2 + 2 + 4 + index_sizes.blob + index_sizes.string))); } else { name = pe_get_dotnet_string( pe, string_offset, str_heap_size, yr_le16toh(*(WORD*) (row_ptr + 4 + 2 + 2 + 2 + 2 + 4 + index_sizes.blob + index_sizes.string))); } // Sometimes it will be a zero length string. This is technically // against the specification but happens from time to time. if (name != NULL && strlen(name) > 0) yr_set_string(name, pe->object, "assembly.culture"); table_offset += row_size * num_rows; break; case BIT_ASSEMBLYPROCESSOR: table_offset += (4) * num_rows; break; case BIT_ASSEMBLYOS: table_offset += (4 + 4 + 4) * num_rows; break; case BIT_ASSEMBLYREF: row_size = (2 + 2 + 2 + 2 + 4 + (index_sizes.blob * 2) + (index_sizes.string * 2)); row_ptr = table_offset; for (i = 0; i < num_rows; i++) { if (!fits_in_pe(pe, row_ptr, row_size)) break; assemblyref_table = (PASSEMBLYREF_TABLE) row_ptr; yr_set_integer( yr_le16toh(assemblyref_table->MajorVersion), pe->object, "assembly_refs[%i].version.major", i); yr_set_integer( yr_le16toh(assemblyref_table->MinorVersion), pe->object, "assembly_refs[%i].version.minor", i); yr_set_integer( yr_le16toh(assemblyref_table->BuildNumber), pe->object, "assembly_refs[%i].version.build_number", i); yr_set_integer( yr_le16toh(assemblyref_table->RevisionNumber), pe->object, "assembly_refs[%i].version.revision_number", i); blob_offset = pe->data + metadata_root + yr_le32toh(streams->blob->Offset); if (index_sizes.blob == 4) blob_offset += yr_le32toh( assemblyref_table->PublicKeyOrToken.PublicKeyOrToken_Long); else blob_offset += yr_le16toh( assemblyref_table->PublicKeyOrToken.PublicKeyOrToken_Short); blob_result = dotnet_parse_blob_entry(pe, blob_offset); blob_offset += blob_result.size; if (blob_result.size == 0 || !fits_in_pe(pe, blob_offset, blob_result.length)) { row_ptr += row_size; continue; } // Avoid empty strings. if (blob_result.length > 0) { yr_set_sized_string( (char*) blob_offset, blob_result.length, pe->object, "assembly_refs[%i].public_key_or_token", i); } // Can't use assemblyref_table here because the PublicKey comes before // Name and is a variable length field. if (index_sizes.string == 4) name = pe_get_dotnet_string( pe, string_offset, str_heap_size, yr_le32toh( *(DWORD*) (row_ptr + 2 + 2 + 2 + 2 + 4 + index_sizes.blob))); else name = pe_get_dotnet_string( pe, string_offset, str_heap_size, yr_le16toh( *(WORD*) (row_ptr + 2 + 2 + 2 + 2 + 4 + index_sizes.blob))); if (name != NULL) yr_set_string(name, pe->object, "assembly_refs[%i].name", i); row_ptr += row_size; } tables.assemblyref.Offset = table_offset; tables.assemblyref.RowCount = num_rows; tables.assemblyref.RowSize = row_size; yr_set_integer(i, pe->object, "number_of_assembly_refs"); table_offset += row_size * num_rows; break; case BIT_ASSEMBLYREFPROCESSOR: table_offset += (4 + index_sizes.assemblyrefprocessor) * num_rows; break; case BIT_ASSEMBLYREFOS: table_offset += (4 + 4 + 4 + index_sizes.assemblyref) * num_rows; break; case BIT_FILE: table_offset += (4 + index_sizes.string + index_sizes.blob) * num_rows; break; case BIT_EXPORTEDTYPE: row_count = max_rows( 3, yr_le32toh(rows.file), yr_le32toh(rows.assemblyref), yr_le32toh(rows.exportedtype)); if (row_count > (0xFFFF >> 0x02)) index_size = 4; else index_size = 2; table_offset += (4 + 4 + (index_sizes.string * 2) + index_size) * num_rows; break; case BIT_MANIFESTRESOURCE: // This is an Implementation coded index with no 3rd bit specified. row_count = max_rows( 2, yr_le32toh(rows.file), yr_le32toh(rows.assemblyref)); if (row_count > (0xFFFF >> 0x02)) index_size = 4; else index_size = 2; row_size = (4 + 4 + index_sizes.string + index_size); row_ptr = table_offset; // First DWORD is the offset. for (i = 0; i < num_rows; i++) { if (!fits_in_pe(pe, row_ptr, row_size)) break; manifestresource_table = (PMANIFESTRESOURCE_TABLE) row_ptr; if (index_size == 4) implementation = yr_le32toh( *(DWORD*) (row_ptr + 4 + 4 + index_sizes.string)); else implementation = yr_le16toh( *(WORD*) (row_ptr + 4 + 4 + index_sizes.string)); row_ptr += row_size; name = pe_get_dotnet_string( pe, string_offset, str_heap_size, DOTNET_STRING_INDEX(manifestresource_table->Name)); if (name != NULL) yr_set_string(name, pe->object, "resources[%i].name", i); // Only set offset and length if it is in this file, otherwise continue // with the next resource. if (implementation != 0) continue; resource_offset = yr_le32toh(manifestresource_table->Offset); if (!fits_in_pe( pe, pe->data + resource_base + resource_offset, sizeof(DWORD))) continue; resource_size = yr_le32toh( *(DWORD*) (pe->data + resource_base + resource_offset)); // Add 4 to skip the size. yr_set_integer( resource_base + resource_offset + 4, pe->object, "resources[%i].offset", i); yr_set_integer(resource_size, pe->object, "resources[%i].length", i); } yr_set_integer(i, pe->object, "number_of_resources"); table_offset += row_size * num_rows; break; case BIT_NESTEDCLASS: row_size = index_sizes.typedef_ * 2; tables.nestedclass.Offset = table_offset; tables.nestedclass.RowCount = num_rows; tables.nestedclass.RowSize = row_size; table_offset += row_size * num_rows; break; case BIT_GENERICPARAM: row_count = max_rows( 2, yr_le32toh(rows.typedef_), yr_le32toh(rows.methoddef)); if (row_count > (0xFFFF >> 0x01)) index_size = 4; else index_size = 2; row_size = (2 + 2 + index_size + index_sizes.string); tables.genericparam.Offset = table_offset; tables.genericparam.RowCount = num_rows; tables.genericparam.RowSize = row_size; table_offset += row_size * num_rows; break; case BIT_METHODSPEC: row_count = max_rows( 2, yr_le32toh(rows.methoddef), yr_le32toh(rows.memberref)); if (row_count > (0xFFFF >> 0x01)) index_size = 4; else index_size = 2; table_offset += (index_size + index_sizes.blob) * num_rows; break; case BIT_GENERICPARAMCONSTRAINT: row_count = max_rows( 3, yr_le32toh(rows.typedef_), yr_le32toh(rows.typeref), yr_le32toh(rows.typespec)); if (row_count > (0xFFFF >> 0x02)) index_size = 4; else index_size = 2; table_offset += (index_sizes.genericparam + index_size) * num_rows; break; default: // printf("Unknown bit: %i\n", bit_check); return; } matched_bits++; } CLASS_CONTEXT class_context = { .pe = pe, .tables = &tables, .index_sizes = &index_sizes, .str_heap = string_offset, .str_size = str_heap_size, .blob_heap = pe->data + streams->metadata_root + yr_le32toh(streams->blob->Offset), .blob_size = yr_le32toh(streams->blob->Size)}; parse_user_types(&class_context); } // Parsing the #~ stream is done in two parts. The first part (this function) // parses enough of the Stream to provide context for the second pass. In // particular it is collecting the number of rows for each of the tables. The // second part parses the actual tables of interest. void dotnet_parse_tilde(PE* pe, PCLI_HEADER cli_header, PSTREAMS streams) { PTILDE_HEADER tilde_header; int64_t resource_base; int64_t metadata_root = streams->metadata_root; uint32_t* row_offset = NULL; int bit_check; // This is used as an offset into the rows and tables. For every bit set in // Valid this will be incremented. This is because the bit position doesn't // matter, just the number of bits that are set, when determining how many // rows and what the table structure is. int matched_bits = 0; // We need to know the number of rows for some tables, because they are // indexed into. The index will be either 2 or 4 bytes, depending upon the // number of rows being indexed into. ROWS rows; INDEX_SIZES index_sizes; uint32_t heap_sizes; // Default all rows to 0. They will be set to actual values later on, if // they exist in the file. memset(&rows, '\0', sizeof(ROWS)); // Default index sizes are 2. Will be bumped to 4 if necessary. memset(&index_sizes, 2, sizeof(index_sizes)); tilde_header = (PTILDE_HEADER) (pe->data + metadata_root + yr_le32toh(streams->tilde->Offset)); if (!struct_fits_in_pe(pe, tilde_header, TILDE_HEADER)) return; heap_sizes = yr_le32toh(tilde_header->HeapSizes); // Set index sizes for various heaps. if (heap_sizes & 0x01) index_sizes.string = 4; if (heap_sizes & 0x02) index_sizes.guid = 4; if (heap_sizes & 0x04) index_sizes.blob = 4; // Immediately after the tilde header is an array of 32bit values which // indicate how many rows are in each table. The tables are immediately // after the rows array. // // Save the row offset. row_offset = (uint32_t*) (tilde_header + 1); // Walk all the bits first because we need to know the number of rows for // some tables in order to parse others. In particular this applies to // coded indexes, which are documented in ECMA-335 II.24.2.6. for (bit_check = 0; bit_check < 64; bit_check++) { if (!((yr_le64toh(tilde_header->Valid) >> bit_check) & 0x01)) continue; #define ROW_CHECK(name) \ if (fits_in_pe(pe, row_offset, (matched_bits + 1) * sizeof(uint32_t))) \ rows.name = *(row_offset + matched_bits); #define ROW_CHECK_WITH_INDEX(name) \ ROW_CHECK(name); \ if (yr_le32toh(rows.name) > 0xFFFF) \ index_sizes.name = 4; switch (bit_check) { case BIT_MODULE: ROW_CHECK_WITH_INDEX(module); break; case BIT_MODULEREF: ROW_CHECK_WITH_INDEX(moduleref); break; case BIT_ASSEMBLYREF: ROW_CHECK_WITH_INDEX(assemblyref); break; case BIT_ASSEMBLYREFPROCESSOR: ROW_CHECK_WITH_INDEX(assemblyrefprocessor); break; case BIT_TYPEREF: ROW_CHECK_WITH_INDEX(typeref); break; case BIT_METHODDEF: ROW_CHECK_WITH_INDEX(methoddef); break; case BIT_MEMBERREF: ROW_CHECK_WITH_INDEX(memberref); break; case BIT_TYPEDEF: ROW_CHECK_WITH_INDEX(typedef_); break; case BIT_TYPESPEC: ROW_CHECK_WITH_INDEX(typespec); break; case BIT_FIELD: ROW_CHECK_WITH_INDEX(field); break; case BIT_PARAM: ROW_CHECK_WITH_INDEX(param); break; case BIT_PROPERTY: ROW_CHECK_WITH_INDEX(property); break; case BIT_INTERFACEIMPL: ROW_CHECK_WITH_INDEX(interfaceimpl); break; case BIT_EVENT: ROW_CHECK_WITH_INDEX(event); break; case BIT_STANDALONESIG: ROW_CHECK(standalonesig); break; case BIT_ASSEMBLY: ROW_CHECK_WITH_INDEX(assembly); break; case BIT_FILE: ROW_CHECK(file); break; case BIT_EXPORTEDTYPE: ROW_CHECK(exportedtype); break; case BIT_MANIFESTRESOURCE: ROW_CHECK(manifestresource); break; case BIT_GENERICPARAM: ROW_CHECK_WITH_INDEX(genericparam); break; case BIT_GENERICPARAMCONSTRAINT: ROW_CHECK(genericparamconstraint); break; case BIT_METHODSPEC: ROW_CHECK_WITH_INDEX(methodspec); break; default: break; } matched_bits++; } // This is used when parsing the MANIFEST RESOURCE table. resource_base = pe_rva_to_offset( pe, yr_le32toh(cli_header->Resources.VirtualAddress)); dotnet_parse_tilde_2( pe, tilde_header, resource_base, rows, index_sizes, streams); } static bool dotnet_is_dotnet(PE* pe) { PIMAGE_DATA_DIRECTORY directory = pe_get_directory_entry( pe, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR); if (!directory) return false; int64_t offset = pe_rva_to_offset(pe, yr_le32toh(directory->VirtualAddress)); if (offset < 0 || !struct_fits_in_pe(pe, pe->data + offset, CLI_HEADER)) return false; CLI_HEADER* cli_header = (CLI_HEADER*) (pe->data + offset); if (yr_le32toh(cli_header->Size) != sizeof(CLI_HEADER)) return false; int64_t metadata_root = pe_rva_to_offset( pe, yr_le32toh(cli_header->MetaData.VirtualAddress)); offset = metadata_root; if (!struct_fits_in_pe(pe, pe->data + metadata_root, NET_METADATA)) return false; NET_METADATA* metadata = (NET_METADATA*) (pe->data + metadata_root); if (yr_le32toh(metadata->Magic) != NET_METADATA_MAGIC) return false; // Version length must be between 1 and 255, and be a multiple of 4. // Also make sure it fits in pe. uint32_t md_len = yr_le32toh(metadata->Length); if (md_len == 0 || md_len > 255 || md_len % 4 != 0 || !fits_in_pe(pe, pe->data + offset + sizeof(NET_METADATA), md_len)) { return false; } if (IS_64BITS_PE(pe)) { if (yr_le32toh(OptionalHeader(pe, NumberOfRvaAndSizes)) < IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR) return false; } return true; } void dotnet_parse_com(PE* pe) { PIMAGE_DATA_DIRECTORY directory; PCLI_HEADER cli_header; PNET_METADATA metadata; int64_t metadata_root, offset; char* end; STREAMS headers; WORD num_streams; uint32_t md_len; if (!dotnet_is_dotnet(pe)) { yr_set_integer(0, pe->object, "is_dotnet"); return; } yr_set_integer(1, pe->object, "is_dotnet"); directory = pe_get_directory_entry(pe, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR); if (directory == NULL) return; offset = pe_rva_to_offset(pe, yr_le32toh(directory->VirtualAddress)); if (offset < 0 || !struct_fits_in_pe(pe, pe->data + offset, CLI_HEADER)) return; cli_header = (PCLI_HEADER) (pe->data + offset); offset = metadata_root = pe_rva_to_offset( pe, yr_le32toh(cli_header->MetaData.VirtualAddress)); if (!struct_fits_in_pe(pe, pe->data + offset, NET_METADATA)) return; metadata = (PNET_METADATA) (pe->data + offset); // Version length must be between 1 and 255, and be a multiple of 4. // Also make sure it fits in pe. md_len = yr_le32toh(metadata->Length); if (md_len == 0 || md_len > 255 || md_len % 4 != 0 || !fits_in_pe(pe, pe->data + offset + sizeof(NET_METADATA), md_len)) { return; } // The length includes the NULL terminator and is rounded up to a multiple of // 4. We need to exclude the terminator and the padding, so search for the // first NULL byte. end = (char*) memmem((void*) metadata->Version, md_len, "\0", 1); if (end != NULL) yr_set_sized_string( metadata->Version, (end - metadata->Version), pe->object, "version"); // The metadata structure has some variable length records after the version. // We must manually parse things from here on out. // // Flags are 2 bytes (always 0). offset += sizeof(NET_METADATA) + md_len + 2; // 2 bytes for Streams. if (!fits_in_pe(pe, pe->data + offset, 2)) return; num_streams = (WORD) * (pe->data + offset); offset += 2; headers = dotnet_parse_stream_headers(pe, offset, metadata_root, num_streams); if (headers.guid != NULL) dotnet_parse_guid(pe, metadata_root, headers.guid); // Parse the #~ stream, which includes various tables of interest. // These tables reference the blob and string streams, so we need to ensure // those are not NULL also. if (headers.tilde != NULL && headers.string != NULL && headers.blob != NULL) dotnet_parse_tilde(pe, cli_header, &headers); if (headers.us != NULL) dotnet_parse_us(pe, metadata_root, headers.us); } begin_declarations declare_integer("is_dotnet"); declare_string("version"); declare_string("module_name"); begin_struct_array("streams") declare_string("name"); declare_integer("offset"); declare_integer("size"); end_struct_array("streams") declare_integer("number_of_streams"); declare_string_array("guids"); declare_integer("number_of_guids"); begin_struct_array("resources") declare_integer("offset"); declare_integer("length"); declare_string("name"); end_struct_array("resources") declare_integer("number_of_resources"); begin_struct_array("classes") declare_string("fullname"); declare_string("name"); declare_string("namespace"); declare_string("visibility"); declare_string("type"); declare_integer("abstract"); declare_integer("sealed"); declare_integer("number_of_generic_parameters"); declare_string_array("generic_parameters"); declare_integer("number_of_base_types"); declare_string_array("base_types"); declare_integer("number_of_methods"); begin_struct_array("methods") declare_string_array("generic_parameters"); declare_integer("number_of_generic_parameters"); begin_struct_array("parameters") declare_string("name"); declare_string("type"); end_struct_array("parameters") declare_integer("number_of_parameters"); declare_string("return_type"); declare_integer("abstract"); declare_integer("final"); declare_integer("virtual"); declare_integer("static"); declare_string("visibility"); declare_string("name"); end_struct_array("methods") end_struct_array("classes") declare_integer("number_of_classes"); begin_struct_array("assembly_refs") begin_struct("version") declare_integer("major"); declare_integer("minor"); declare_integer("build_number"); declare_integer("revision_number"); end_struct("version") declare_string("public_key_or_token"); declare_string("name"); end_struct_array("assembly_refs") declare_integer("number_of_assembly_refs"); begin_struct("assembly") begin_struct("version") declare_integer("major"); declare_integer("minor"); declare_integer("build_number"); declare_integer("revision_number"); end_struct("version") declare_string("name"); declare_string("culture"); end_struct("assembly") declare_string_array("modulerefs"); declare_integer("number_of_modulerefs"); declare_string_array("user_strings"); declare_integer("number_of_user_strings"); declare_string("typelib"); declare_string_array("constants"); declare_integer("number_of_constants"); declare_integer_array("field_offsets"); declare_integer("number_of_field_offsets"); end_declarations int module_initialize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_finalize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { YR_MEMORY_BLOCK* block; YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; const uint8_t* block_data = NULL; foreach_memory_block(iterator, block) { PIMAGE_NT_HEADERS32 pe_header; block_data = yr_fetch_block_data(block); if (block_data == NULL) continue; pe_header = pe_get_header(block_data, block->size); if (pe_header != NULL) { // Ignore DLLs while scanning a process if (!(context->flags & SCAN_FLAGS_PROCESS_MEMORY) || !(pe_header->FileHeader.Characteristics & IMAGE_FILE_DLL)) { PE* pe = (PE*) yr_malloc(sizeof(PE)); if (pe == NULL) return ERROR_INSUFFICIENT_MEMORY; pe->data = block_data; pe->data_size = block->size; pe->object = module_object; pe->header = pe_header; module_object->data = pe; dotnet_parse_com(pe); break; } } } return ERROR_SUCCESS; } int module_unload(YR_OBJECT* module_object) { PE* pe = (PE*) module_object->data; if (pe == NULL) return ERROR_SUCCESS; yr_free(pe); return ERROR_SUCCESS; } yara-4.5.3/libyara/modules/elf/000077500000000000000000000000001501365277300163315ustar00rootroot00000000000000yara-4.5.3/libyara/modules/elf/elf.c000066400000000000000000001771201501365277300172530ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include "../crypto.h" #include "../exception.h" #define MODULE_NAME elf #define CLASS_DATA(c, d) ((c << 8) | d) static int sort_strcmp(const void* a, const void* b) { return strcmp(*(const char**) a, *(const char**) b); } define_function(telfhash) { YR_OBJECT* obj = yr_module(); ELF* elf = (ELF*) obj->data; if (elf == NULL) return_string(YR_UNDEFINED); if (elf->telfhash) return_string(elf->telfhash); /* We prefer dynsym if possible */ ELF_SYMBOL_LIST* list = elf->dynsym ? elf->dynsym : elf->symtab; if (!list) return_string(YR_UNDEFINED); /* exclusions are based on the original implementation https://github.com/trendmicro/telfhash/blob/master/telfhash/telfhash.py */ char* exclude_strings[] = { "__libc_start_main", "main", "abort", "cachectl", "cacheflush", "puts", "atol", "malloc_trim"}; SIMPLE_STR* sstr = NULL; Tlsh* tlsh = NULL; int symbol_count = 0; char** clean_names = yr_calloc(list->count, sizeof(*clean_names)); if (clean_names == NULL && list->count > 0) return_string(YR_UNDEFINED); for (ELF_SYMBOL* i = list->symbols; i != NULL; i = i->next) { char* name = i->name; if (!name) continue; /* Use only global code symbols */ if (i->bind != ELF_STB_GLOBAL || i->type != ELF_STT_FUNC || i->visibility != ELF_STV_DEFAULT) continue; /* ignore: x86-64 specific functions string functions (str.* and mem.*), gcc changes them depending on arch symbols starting with . or _ */ bool is_bad_prefix = name[0] == '.' || name[0] == '_'; size_t namelen = strlen(name); bool is_x86_64 = namelen >= 2 && strncmp(name + namelen - 2, "64", 2) == 0; bool is_mem_or_str = strncmp(name, "str", 3) == 0 || strncmp(name, "mem", 3) == 0; if (is_bad_prefix || is_x86_64 || is_mem_or_str) continue; /* Exclude any symbols that match the excluded ones */ bool is_excluded = false; for (int i = 0; i < sizeof(exclude_strings) / sizeof(*exclude_strings); i++) { if (strcmp(name, exclude_strings[i]) == 0) { is_excluded = true; break; } } if (is_excluded) continue; clean_names[symbol_count] = yr_malloc(strlen(name) + 1); if (!clean_names[symbol_count]) goto cleanup; /* Convert it to lowercase */ int j; for (j = 0; name[j]; j++) clean_names[symbol_count][j] = tolower(name[j]); clean_names[symbol_count][j] = '\0'; symbol_count++; } if (!symbol_count) goto cleanup; /* Now we have all the valid symbols, sort them, concat them */ qsort(clean_names, symbol_count, sizeof(*clean_names), &sort_strcmp); sstr = sstr_newf("%s", clean_names[0]); if (!sstr) goto cleanup; /* We've already written first symbol, start at 1 */ for (int i = 1; i < symbol_count; ++i) { if (!sstr_appendf(sstr, ",%s", clean_names[i])) goto cleanup; } tlsh = tlsh_new(); if (!tlsh) goto cleanup; tlsh_final(tlsh, (const unsigned char*) sstr->str, sstr->len, 0); const char* telfhash = tlsh_get_hash(tlsh, true); elf->telfhash = yr_strdup(telfhash); // cache it if (!elf->telfhash) goto cleanup; for (int i = 0; i < symbol_count; ++i) yr_free(clean_names[i]); yr_free(clean_names); sstr_free(sstr); tlsh_free(tlsh); return_string(elf->telfhash); cleanup: for (int i = 0; i < symbol_count; ++i) yr_free(clean_names[i]); yr_free(clean_names); sstr_free(sstr); tlsh_free(tlsh); return_string(YR_UNDEFINED); } #if defined(HAVE_LIBCRYPTO) || defined(HAVE_WINCRYPT_H) || \ defined(HAVE_COMMONCRYPTO_COMMONCRYPTO_H) define_function(import_md5) { YR_OBJECT* obj = yr_module(); ELF* elf = (ELF*) obj->data; if (elf == NULL) return_string(YR_UNDEFINED); if (elf->import_hash) return_string(elf->import_hash); ELF_SYMBOL_LIST* list = elf->dynsym ? elf->dynsym : elf->symtab; if (!list) return_string(YR_UNDEFINED); SIMPLE_STR* sstr = NULL; int symbol_count = 0; char** clean_names = yr_malloc(list->count * sizeof(*clean_names)); if (!clean_names) return_string(YR_UNDEFINED); for (ELF_SYMBOL* i = list->symbols; i != NULL; i = i->next) { char* name = i->name; if (!name) continue; if (i->shndx != ELF_SHN_UNDEF) continue; // skip empty names if (strlen(i->name) == 0) continue; clean_names[symbol_count] = yr_malloc(strlen(name) + 1); if (!clean_names[symbol_count]) goto cleanup; /* Convert it to lowercase */ int j; for (j = 0; name[j]; j++) clean_names[symbol_count][j] = tolower(name[j]); clean_names[symbol_count][j] = '\0'; symbol_count++; } if (!symbol_count) goto cleanup; /* Now we have all the valid symbols, sort them, concat them */ qsort(clean_names, symbol_count, sizeof(*clean_names), &sort_strcmp); sstr = sstr_newf("%s", clean_names[0]); if (!sstr) goto cleanup; /* We've already written first symbol, start at 1 */ for (int i = 1; i < symbol_count; ++i) { if (!sstr_appendf(sstr, ",%s", clean_names[i])) goto cleanup; } unsigned char hash[YR_MD5_LEN]; yr_md5_ctx ctx; yr_md5_init(&ctx); yr_md5_update(&ctx, sstr->str, sstr->len); yr_md5_final(hash, &ctx); elf->import_hash = yr_malloc(YR_MD5_LEN * 2 + 1); if (!elf->import_hash) goto cleanup; for (int i = 0; i < YR_MD5_LEN; ++i) sprintf(elf->import_hash + (i * 2), "%02x", hash[i]); for (int i = 0; i < symbol_count; ++i) yr_free(clean_names[i]); yr_free(clean_names); sstr_free(sstr); return_string(elf->import_hash); cleanup: for (int i = 0; i < symbol_count; ++i) yr_free(clean_names[i]); yr_free(clean_names); sstr_free(sstr); return_string(YR_UNDEFINED); } #endif // defined(HAVE_LIBCRYPTO) || defined(HAVE_WINCRYPT_H) int get_elf_class_data(const uint8_t* buffer, size_t buffer_length) { elf_ident_t* elf_ident; if (buffer_length < sizeof(elf_ident_t)) return 0; elf_ident = (elf_ident_t*) buffer; if (yr_le32toh(elf_ident->magic) == ELF_MAGIC) { return CLASS_DATA(elf_ident->_class, elf_ident->data); } else { return 0; } } static bool is_valid_ptr( const void* base, size_t size, const void* ptr, uint64_t ptr_size) // ptr_size can be 64bit even in 32bit systems. { return ptr >= base && ptr_size <= size && ((char*) ptr) + ptr_size <= ((char*) base) + size; } #define IS_VALID_PTR(base, size, ptr) \ is_valid_ptr(base, size, ptr, sizeof(*ptr)) // // Returns a string table entry for the index or NULL if the entry is out // of bounds. A non-null return value will be a null-terminated C string. // static const char* str_table_entry( const char* str_table_base, const char* str_table_limit, int index) { size_t len; const char* str_entry; if (str_table_base >= str_table_limit) return NULL; // The first entry in the string table must be a null character, if not the // string table is probably corrupted. if (*str_table_base != '\0') return NULL; if (index < 0) return NULL; str_entry = str_table_base + index; if (str_entry >= str_table_limit) return NULL; len = strnlen(str_entry, str_table_limit - str_entry); // Entry is clamped by extent of string table, not null-terminated. if (str_entry + len == str_table_limit) return NULL; return str_entry; } #define ELF_SIZE_OF_SECTION_TABLE(bits, bo, h) \ (sizeof(elf##bits##_section_header_t) * yr_##bo##16toh(h->sh_entry_count)) #define ELF_SIZE_OF_PROGRAM_TABLE(bits, bo, h) \ (sizeof(elf##bits##_program_header_t) * yr_##bo##16toh(h->ph_entry_count)) #define ELF_RVA_TO_OFFSET(bits, bo) \ uint64_t elf_rva_to_offset_##bits##_##bo( \ elf##bits##_header_t* elf_header, uint64_t rva, size_t elf_size) \ { \ if (yr_##bo##16toh(elf_header->type) == ELF_ET_EXEC) \ { \ int i; \ \ elf##bits##_program_header_t* program; \ \ /* check that ph_offset doesn't wrap when added to SIZE_OF_PROGRAM_TABLE \ */ \ \ if (ULONG_MAX - yr_##bo##bits##toh(elf_header->ph_offset) < \ ELF_SIZE_OF_PROGRAM_TABLE(bits, bo, elf_header)) \ { \ return YR_UNDEFINED; \ } \ \ if (yr_##bo##bits##toh(elf_header->ph_offset) == 0 || \ yr_##bo##bits##toh(elf_header->ph_offset) > elf_size || \ yr_##bo##bits##toh(elf_header->ph_offset) + \ ELF_SIZE_OF_PROGRAM_TABLE(bits, bo, elf_header) > \ elf_size || \ yr_##bo##16toh(elf_header->ph_entry_count) == 0) \ { \ return YR_UNDEFINED; \ } \ \ program = (elf##bits##_program_header_t*) \ ((uint8_t*) elf_header + yr_##bo##bits##toh(elf_header->ph_offset)); \ \ for (i = 0; i < yr_##bo##16toh(elf_header->ph_entry_count); i++) \ { \ if (rva >= yr_##bo##bits##toh(program->virt_addr) && \ rva < yr_##bo##bits##toh(program->virt_addr) + \ yr_##bo##bits##toh(program->mem_size)) \ { \ return yr_##bo##bits##toh(program->offset) + \ (rva - yr_##bo##bits##toh(program->virt_addr)); \ } \ \ program++; \ } \ } \ else \ { \ int i; \ \ elf##bits##_section_header_t* section; \ \ /* check that sh_offset doesn't wrap when added to SIZE_OF_SECTION_TABLE \ */ \ \ if (ULONG_MAX - yr_##bo##bits##toh(elf_header->sh_offset) < \ ELF_SIZE_OF_SECTION_TABLE(bits, bo, elf_header)) \ { \ return YR_UNDEFINED; \ } \ \ if (yr_##bo##bits##toh(elf_header->sh_offset) == 0 || \ yr_##bo##bits##toh(elf_header->sh_offset) > elf_size || \ yr_##bo##bits##toh(elf_header->sh_offset) + \ ELF_SIZE_OF_SECTION_TABLE(bits, bo, elf_header) > \ elf_size || \ yr_##bo##16toh(elf_header->sh_entry_count) == 0) \ { \ return YR_UNDEFINED; \ } \ \ section = (elf##bits##_section_header_t*) \ ((uint8_t*) elf_header + yr_##bo##bits##toh(elf_header->sh_offset)); \ \ for (i = 0; i < yr_##bo##16toh(elf_header->sh_entry_count); i++) \ { \ if (yr_##bo##32toh(section->type) != ELF_SHT_NULL && \ yr_##bo##32toh(section->type) != ELF_SHT_NOBITS && \ rva >= yr_##bo##bits##toh(section->addr) && \ rva < yr_##bo##bits##toh(section->addr) + \ yr_##bo##bits##toh(section->size)) \ { \ return yr_##bo##bits##toh(section->offset) + \ (rva - yr_##bo##bits##toh(section->addr)); \ } \ \ section++; \ } \ } \ return YR_UNDEFINED; \ } #define PARSE_ELF_HEADER(bits, bo) \ int parse_elf_header_##bits##_##bo( \ ELF* elf_data, \ elf##bits##_header_t* elf, \ uint64_t base_address, \ size_t elf_size, \ int flags, \ YR_OBJECT* elf_obj) \ { \ unsigned int i, j, m; \ const char* elf_raw = (const char*) elf; \ uint16_t str_table_index = yr_##bo##16toh(elf->sh_str_table_index); \ \ const char* sym_table = NULL; \ const char* sym_str_table = NULL; \ const char* dyn_sym_table = NULL; \ const char* dyn_sym_str_table = NULL; \ \ uint##bits##_t sym_table_size = 0; \ uint##bits##_t sym_str_table_size = 0; \ uint##bits##_t dyn_sym_table_size = 0; \ uint##bits##_t dyn_sym_str_table_size = 0; \ \ elf_data->symtab = elf_data->dynsym = NULL; \ \ elf##bits##_section_header_t* section_table; \ elf##bits##_section_header_t* section; \ elf##bits##_program_header_t* segment; \ \ yr_set_integer(yr_##bo##16toh(elf->type), elf_obj, "type"); \ yr_set_integer(yr_##bo##16toh(elf->machine), elf_obj, "machine"); \ yr_set_integer(yr_##bo##bits##toh(elf->sh_offset), elf_obj, "sh_offset"); \ yr_set_integer( \ yr_##bo##16toh(elf->sh_entry_size), elf_obj, "sh_entry_size"); \ yr_set_integer( \ yr_##bo##16toh(elf->sh_entry_count), elf_obj, "number_of_sections"); \ yr_set_integer(yr_##bo##bits##toh(elf->ph_offset), elf_obj, "ph_offset"); \ yr_set_integer( \ yr_##bo##16toh(elf->ph_entry_size), elf_obj, "ph_entry_size"); \ yr_set_integer( \ yr_##bo##16toh(elf->ph_entry_count), elf_obj, "number_of_segments"); \ \ if (yr_##bo##bits##toh(elf->entry) != 0) \ { \ yr_set_integer( \ flags& SCAN_FLAGS_PROCESS_MEMORY \ ? base_address + yr_##bo##bits##toh(elf->entry) \ : elf_rva_to_offset_##bits##_##bo( \ elf, yr_##bo##bits##toh(elf->entry), elf_size), \ elf_obj, \ "entry_point"); \ } \ \ if (yr_##bo##16toh(elf->sh_entry_count) < ELF_SHN_LORESERVE && \ str_table_index < yr_##bo##16toh(elf->sh_entry_count) && \ yr_##bo##bits##toh(elf->sh_offset) < elf_size && \ yr_##bo##bits##toh(elf->sh_offset) + \ yr_##bo##16toh(elf->sh_entry_count) * \ sizeof(elf##bits##_section_header_t) <= \ elf_size) \ { \ const char* str_table = NULL; \ \ section_table = \ (elf##bits##_section_header_t*) (elf_raw + yr_##bo##bits##toh(elf->sh_offset)); \ \ if (yr_##bo##bits##toh(section_table[str_table_index].offset) < \ elf_size) \ { \ str_table = elf_raw + \ yr_##bo##bits##toh(section_table[str_table_index].offset); \ } \ \ section = section_table; \ \ for (i = 0; i < yr_##bo##16toh(elf->sh_entry_count); i++, section++) \ { \ yr_set_integer( \ yr_##bo##32toh(section->type), elf_obj, "sections[%i].type", i); \ yr_set_integer( \ yr_##bo##bits##toh(section->flags), \ elf_obj, \ "sections[%i].flags", \ i); \ yr_set_integer( \ yr_##bo##bits##toh(section->addr), \ elf_obj, \ "sections[%i].address", \ i); \ yr_set_integer( \ yr_##bo##bits##toh(section->size), \ elf_obj, \ "sections[%i].size", \ i); \ yr_set_integer( \ yr_##bo##bits##toh(section->offset), \ elf_obj, \ "sections[%i].offset", \ i); \ \ if (yr_##bo##32toh(section->name) < elf_size && str_table > elf_raw) \ { \ const char* section_name = str_table_entry( \ str_table, elf_raw + elf_size, yr_##bo##32toh(section->name)); \ \ if (section_name) \ yr_set_string(section_name, elf_obj, "sections[%i].name", i); \ } \ \ if (yr_##bo##32toh(section->type) == ELF_SHT_SYMTAB && \ yr_##bo##32toh(section->link) < elf->sh_entry_count) \ { \ elf##bits##_section_header_t* string_section = section_table + \ yr_##bo##32toh( \ section->link); \ \ if (IS_VALID_PTR(elf, elf_size, string_section) && \ yr_##bo##32toh(string_section->type) == ELF_SHT_STRTAB) \ { \ sym_table = elf_raw + yr_##bo##bits##toh(section->offset); \ sym_str_table = elf_raw + \ yr_##bo##bits##toh(string_section->offset); \ sym_table_size = yr_##bo##bits##toh(section->size); \ sym_str_table_size = yr_##bo##bits##toh(string_section->size); \ } \ } \ \ if (yr_##bo##32toh(section->type) == ELF_SHT_DYNSYM && \ yr_##bo##32toh(section->link) < elf->sh_entry_count) \ { \ elf##bits##_section_header_t* dynstr_section = section_table + \ yr_##bo##32toh( \ section->link); \ \ if (IS_VALID_PTR(elf, elf_size, dynstr_section) && \ yr_##bo##32toh(dynstr_section->type) == ELF_SHT_STRTAB) \ { \ dyn_sym_table = elf_raw + yr_##bo##bits##toh(section->offset); \ dyn_sym_str_table = elf_raw + \ yr_##bo##bits##toh(dynstr_section->offset); \ dyn_sym_table_size = yr_##bo##bits##toh(section->size); \ dyn_sym_str_table_size = yr_##bo##bits##toh(dynstr_section->size); \ } \ } \ } \ \ if (is_valid_ptr(elf, elf_size, sym_str_table, sym_str_table_size) && \ is_valid_ptr(elf, elf_size, sym_table, sym_table_size)) \ { \ elf##bits##_sym_t* sym = (elf##bits##_sym_t*) sym_table; \ elf_data->symtab = (ELF_SYMBOL_LIST*) yr_malloc( \ sizeof(ELF_SYMBOL_LIST)); \ \ if (elf_data->symtab == NULL) \ return ERROR_INSUFFICIENT_MEMORY; \ \ ELF_SYMBOL** symbol = &(elf_data->symtab->symbols); \ *symbol = NULL; \ \ for (j = 0; j < sym_table_size / sizeof(elf##bits##_sym_t); \ j++, sym++) \ { \ *symbol = (ELF_SYMBOL*) yr_malloc(sizeof(ELF_SYMBOL)); \ if (*symbol == NULL) \ return ERROR_INSUFFICIENT_MEMORY; \ \ (*symbol)->name = NULL; \ (*symbol)->next = NULL; \ \ const char* sym_name = str_table_entry( \ sym_str_table, \ sym_str_table + sym_str_table_size, \ yr_##bo##32toh(sym->name)); \ \ if (sym_name) \ { \ yr_set_string(sym_name, elf_obj, "symtab[%i].name", j); \ (*symbol)->name = (char*) yr_malloc(strlen(sym_name) + 1); \ if ((*symbol)->name == NULL) \ return ERROR_INSUFFICIENT_MEMORY; \ \ strcpy((*symbol)->name, sym_name); \ } \ \ int bind = sym->info >> 4; \ (*symbol)->bind = bind; \ yr_set_integer(bind, elf_obj, "symtab[%i].bind", j); \ \ int type = sym->info & 0xf; \ (*symbol)->type = type; \ yr_set_integer(type, elf_obj, "symtab[%i].type", j); \ \ int shndx = yr_##bo##16toh(sym->shndx); \ (*symbol)->shndx = shndx; \ yr_set_integer(shndx, elf_obj, "symtab[%i].shndx", j); \ \ int value = yr_##bo##bits##toh(sym->value); \ (*symbol)->value = value; \ yr_set_integer( \ yr_##bo##bits##toh(sym->value), elf_obj, "symtab[%i].value", j); \ \ int size = yr_##bo##bits##toh(sym->size); \ (*symbol)->size = size; \ yr_set_integer( \ yr_##bo##bits##toh(sym->size), elf_obj, "symtab[%i].size", j); \ \ (*symbol)->visibility = sym->other & 0x3; \ \ symbol = &((*symbol)->next); \ } \ \ elf_data->symtab->count = j; \ yr_set_integer(j, elf_obj, "symtab_entries"); \ } \ \ if (is_valid_ptr( \ elf, elf_size, dyn_sym_str_table, dyn_sym_str_table_size) && \ is_valid_ptr(elf, elf_size, dyn_sym_table, dyn_sym_table_size)) \ { \ elf##bits##_sym_t* dynsym = (elf##bits##_sym_t*) dyn_sym_table; \ \ elf_data->dynsym = (ELF_SYMBOL_LIST*) yr_malloc( \ sizeof(ELF_SYMBOL_LIST)); \ \ if (elf_data->dynsym == NULL) \ return ERROR_INSUFFICIENT_MEMORY; \ \ ELF_SYMBOL** symbol = &(elf_data->dynsym->symbols); \ *symbol = NULL; \ \ for (m = 0; m < dyn_sym_table_size / sizeof(elf##bits##_sym_t); \ m++, dynsym++) \ { \ *symbol = (ELF_SYMBOL*) yr_malloc(sizeof(ELF_SYMBOL)); \ if (*symbol == NULL) \ return ERROR_INSUFFICIENT_MEMORY; \ \ (*symbol)->name = NULL; \ (*symbol)->next = NULL; \ \ const char* dynsym_name = str_table_entry( \ dyn_sym_str_table, \ dyn_sym_str_table + dyn_sym_str_table_size, \ yr_##bo##32toh(dynsym->name)); \ \ if (dynsym_name) \ { \ yr_set_string(dynsym_name, elf_obj, "dynsym[%i].name", m); \ (*symbol)->name = (char*) yr_malloc(strlen(dynsym_name) + 1); \ if ((*symbol)->name == NULL) \ return ERROR_INSUFFICIENT_MEMORY; \ \ strcpy((*symbol)->name, dynsym_name); \ } \ \ int bind = dynsym->info >> 4; \ (*symbol)->bind = bind; \ yr_set_integer(dynsym->info >> 4, elf_obj, "dynsym[%i].bind", m); \ \ int type = dynsym->info & 0xf; \ (*symbol)->type = type; \ yr_set_integer(dynsym->info & 0xf, elf_obj, "dynsym[%i].type", m); \ \ int shndx = yr_##bo##16toh(dynsym->shndx); \ (*symbol)->shndx = shndx; \ yr_set_integer( \ yr_##bo##16toh(dynsym->shndx), elf_obj, "dynsym[%i].shndx", m); \ \ int value = yr_##bo##bits##toh(dynsym->value); \ (*symbol)->value = value; \ yr_set_integer( \ yr_##bo##bits##toh(dynsym->value), \ elf_obj, \ "dynsym[%i].value", \ m); \ \ int size = yr_##bo##bits##toh(dynsym->size); \ (*symbol)->size = size; \ yr_set_integer( \ yr_##bo##bits##toh(dynsym->size), \ elf_obj, \ "dynsym[%i].size", \ m); \ \ (*symbol)->visibility = dynsym->other & 0x3; \ \ symbol = &((*symbol)->next); \ } \ \ elf_data->dynsym->count = m; \ yr_set_integer(m, elf_obj, "dynsym_entries"); \ } \ } \ \ if (yr_##bo##16toh(elf->ph_entry_count) > 0 && \ yr_##bo##16toh(elf->ph_entry_count) < ELF_PN_XNUM && \ yr_##bo##bits##toh(elf->ph_offset) < elf_size && \ yr_##bo##bits##toh(elf->ph_offset) + \ yr_##bo##16toh(elf->ph_entry_count) * \ sizeof(elf##bits##_program_header_t) <= \ elf_size) \ { \ segment = \ (elf##bits##_program_header_t*) (elf_raw + yr_##bo##bits##toh(elf->ph_offset)); \ \ for (i = 0; i < yr_##bo##16toh(elf->ph_entry_count); i++, segment++) \ { \ yr_set_integer( \ yr_##bo##32toh(segment->type), elf_obj, "segments[%i].type", i); \ yr_set_integer( \ yr_##bo##32toh(segment->flags), elf_obj, "segments[%i].flags", i); \ yr_set_integer( \ yr_##bo##bits##toh(segment->offset), \ elf_obj, \ "segments[%i].offset", \ i); \ yr_set_integer( \ yr_##bo##bits##toh(segment->virt_addr), \ elf_obj, \ "segments[%i].virtual_address", \ i); \ yr_set_integer( \ yr_##bo##bits##toh(segment->phys_addr), \ elf_obj, \ "segments[%i].physical_address", \ i); \ yr_set_integer( \ yr_##bo##bits##toh(segment->file_size), \ elf_obj, \ "segments[%i].file_size", \ i); \ yr_set_integer( \ yr_##bo##bits##toh(segment->mem_size), \ elf_obj, \ "segments[%i].memory_size", \ i); \ yr_set_integer( \ yr_##bo##bits##toh(segment->alignment), \ elf_obj, \ "segments[%i].alignment", \ i); \ \ if (yr_##bo##32toh(segment->type) == ELF_PT_DYNAMIC) \ { \ j = 0; \ if (yr_##bo##bits##toh(segment->offset) < elf_size) \ { \ elf##bits##_dyn_t* dyn = \ (elf##bits##_dyn_t*) (elf_raw + yr_##bo##bits##toh(segment->offset)); \ \ for (j = 0; IS_VALID_PTR(elf, elf_size, dyn); dyn++, j++) \ { \ yr_set_integer( \ yr_##bo##bits##toh(dyn->tag), elf_obj, "dynamic[%i].type", j); \ yr_set_integer( \ yr_##bo##bits##toh(dyn->val), elf_obj, "dynamic[%i].val", j); \ \ if (dyn->tag == ELF_DT_NULL) \ { \ j++; \ break; \ } \ } \ } \ yr_set_integer(j, elf_obj, "dynamic_section_entries"); \ } \ } \ } \ return ERROR_SUCCESS; \ } ELF_RVA_TO_OFFSET(32, le); ELF_RVA_TO_OFFSET(64, le); ELF_RVA_TO_OFFSET(32, be); ELF_RVA_TO_OFFSET(64, be); PARSE_ELF_HEADER(32, le); PARSE_ELF_HEADER(64, le); PARSE_ELF_HEADER(32, be); PARSE_ELF_HEADER(64, be); begin_declarations declare_integer("ET_NONE"); declare_integer("ET_REL"); declare_integer("ET_EXEC"); declare_integer("ET_DYN"); declare_integer("ET_CORE"); declare_integer("EM_NONE"); declare_integer("EM_M32"); declare_integer("EM_SPARC"); declare_integer("EM_386"); declare_integer("EM_68K"); declare_integer("EM_88K"); declare_integer("EM_860"); declare_integer("EM_MIPS"); declare_integer("EM_MIPS_RS3_LE"); declare_integer("EM_PPC"); declare_integer("EM_PPC64"); declare_integer("EM_ARM"); declare_integer("EM_X86_64"); declare_integer("EM_AARCH64"); declare_integer("SHT_NULL"); declare_integer("SHT_PROGBITS"); declare_integer("SHT_SYMTAB"); declare_integer("SHT_STRTAB"); declare_integer("SHT_RELA"); declare_integer("SHT_HASH"); declare_integer("SHT_DYNAMIC"); declare_integer("SHT_NOTE"); declare_integer("SHT_NOBITS"); declare_integer("SHT_REL"); declare_integer("SHT_SHLIB"); declare_integer("SHT_DYNSYM"); declare_integer("SHF_WRITE"); declare_integer("SHF_ALLOC"); declare_integer("SHF_EXECINSTR"); declare_integer("type"); declare_integer("machine"); declare_integer("entry_point"); declare_integer("number_of_sections"); declare_integer("sh_offset"); declare_integer("sh_entry_size"); declare_integer("number_of_segments"); declare_integer("ph_offset"); declare_integer("ph_entry_size"); begin_struct_array("sections") declare_integer("type"); declare_integer("flags"); declare_integer("address"); declare_string("name"); declare_integer("size"); declare_integer("offset"); end_struct_array("sections") declare_integer("PT_NULL"); declare_integer("PT_LOAD"); declare_integer("PT_DYNAMIC"); declare_integer("PT_INTERP"); declare_integer("PT_NOTE"); declare_integer("PT_SHLIB"); declare_integer("PT_PHDR"); declare_integer("PT_TLS"); declare_integer("PT_GNU_EH_FRAME"); declare_integer("PT_GNU_STACK"); declare_integer("DT_NULL"); declare_integer("DT_NEEDED"); declare_integer("DT_PLTRELSZ"); declare_integer("DT_PLTGOT"); declare_integer("DT_HASH"); declare_integer("DT_STRTAB"); declare_integer("DT_SYMTAB"); declare_integer("DT_RELA"); declare_integer("DT_RELASZ"); declare_integer("DT_RELAENT"); declare_integer("DT_STRSZ"); declare_integer("DT_SYMENT"); declare_integer("DT_INIT"); declare_integer("DT_FINI"); declare_integer("DT_SONAME"); declare_integer("DT_RPATH"); declare_integer("DT_SYMBOLIC"); declare_integer("DT_REL"); declare_integer("DT_RELSZ"); declare_integer("DT_RELENT"); declare_integer("DT_PLTREL"); declare_integer("DT_DEBUG"); declare_integer("DT_TEXTREL"); declare_integer("DT_JMPREL"); declare_integer("DT_BIND_NOW"); declare_integer("DT_INIT_ARRAY"); declare_integer("DT_FINI_ARRAY"); declare_integer("DT_INIT_ARRAYSZ"); declare_integer("DT_FINI_ARRAYSZ"); declare_integer("DT_RUNPATH"); declare_integer("DT_FLAGS"); declare_integer("DT_ENCODING"); declare_integer("STT_NOTYPE"); declare_integer("STT_OBJECT"); declare_integer("STT_FUNC"); declare_integer("STT_SECTION"); declare_integer("STT_FILE"); declare_integer("STT_COMMON"); declare_integer("STT_TLS"); declare_integer("STB_LOCAL"); declare_integer("STB_GLOBAL"); declare_integer("STB_WEAK"); declare_integer("PF_X"); declare_integer("PF_W"); declare_integer("PF_R"); begin_struct_array("segments") declare_integer("type"); declare_integer("flags"); declare_integer("offset"); declare_integer("virtual_address"); declare_integer("physical_address"); declare_integer("file_size"); declare_integer("memory_size"); declare_integer("alignment"); end_struct_array("segments") declare_integer("dynamic_section_entries"); begin_struct_array("dynamic") declare_integer("type"); declare_integer("val"); end_struct_array("dynamic") declare_integer("symtab_entries"); begin_struct_array("symtab") declare_string("name"); declare_integer("value"); declare_integer("size"); declare_integer("type"); declare_integer("bind"); declare_integer("shndx"); end_struct_array("symtab") declare_integer("dynsym_entries"); begin_struct_array("dynsym") declare_string("name"); declare_integer("value"); declare_integer("size"); declare_integer("type"); declare_integer("bind"); declare_integer("shndx"); end_struct_array("dynsym") declare_function("telfhash", "", "s", telfhash); #if defined(HAVE_LIBCRYPTO) || defined(HAVE_WINCRYPT_H) || \ defined(HAVE_COMMONCRYPTO_COMMONCRYPTO_H) declare_function("import_md5", "", "s", import_md5); #endif // defined(HAVE_LIBCRYPTO) || defined(HAVE_WINCRYPT_H) end_declarations int module_initialize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_finalize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { YR_MEMORY_BLOCK* block; YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; elf32_header_t* elf_header32; elf64_header_t* elf_header64; yr_set_integer(ELF_ET_NONE, module_object, "ET_NONE"); yr_set_integer(ELF_ET_REL, module_object, "ET_REL"); yr_set_integer(ELF_ET_EXEC, module_object, "ET_EXEC"); yr_set_integer(ELF_ET_DYN, module_object, "ET_DYN"); yr_set_integer(ELF_ET_CORE, module_object, "ET_CORE"); yr_set_integer(ELF_EM_NONE, module_object, "EM_NONE"); yr_set_integer(ELF_EM_M32, module_object, "EM_M32"); yr_set_integer(ELF_EM_SPARC, module_object, "EM_SPARC"); yr_set_integer(ELF_EM_386, module_object, "EM_386"); yr_set_integer(ELF_EM_68K, module_object, "EM_68K"); yr_set_integer(ELF_EM_88K, module_object, "EM_88K"); yr_set_integer(ELF_EM_860, module_object, "EM_860"); yr_set_integer(ELF_EM_MIPS, module_object, "EM_MIPS"); yr_set_integer(ELF_EM_MIPS_RS3_LE, module_object, "EM_MIPS_RS3_LE"); yr_set_integer(ELF_EM_PPC, module_object, "EM_PPC"); yr_set_integer(ELF_EM_PPC64, module_object, "EM_PPC64"); yr_set_integer(ELF_EM_ARM, module_object, "EM_ARM"); yr_set_integer(ELF_EM_X86_64, module_object, "EM_X86_64"); yr_set_integer(ELF_EM_AARCH64, module_object, "EM_AARCH64"); yr_set_integer(ELF_SHT_NULL, module_object, "SHT_NULL"); yr_set_integer(ELF_SHT_PROGBITS, module_object, "SHT_PROGBITS"); yr_set_integer(ELF_SHT_SYMTAB, module_object, "SHT_SYMTAB"); yr_set_integer(ELF_SHT_STRTAB, module_object, "SHT_STRTAB"); yr_set_integer(ELF_SHT_RELA, module_object, "SHT_RELA"); yr_set_integer(ELF_SHT_HASH, module_object, "SHT_HASH"); yr_set_integer(ELF_SHT_DYNAMIC, module_object, "SHT_DYNAMIC"); yr_set_integer(ELF_SHT_NOTE, module_object, "SHT_NOTE"); yr_set_integer(ELF_SHT_NOBITS, module_object, "SHT_NOBITS"); yr_set_integer(ELF_SHT_REL, module_object, "SHT_REL"); yr_set_integer(ELF_SHT_SHLIB, module_object, "SHT_SHLIB"); yr_set_integer(ELF_SHT_DYNSYM, module_object, "SHT_DYNSYM"); yr_set_integer(ELF_SHF_WRITE, module_object, "SHF_WRITE"); yr_set_integer(ELF_SHF_ALLOC, module_object, "SHF_ALLOC"); yr_set_integer(ELF_SHF_EXECINSTR, module_object, "SHF_EXECINSTR"); yr_set_integer(ELF_PT_NULL, module_object, "PT_NULL"); yr_set_integer(ELF_PT_LOAD, module_object, "PT_LOAD"); yr_set_integer(ELF_PT_DYNAMIC, module_object, "PT_DYNAMIC"); yr_set_integer(ELF_PT_INTERP, module_object, "PT_INTERP"); yr_set_integer(ELF_PT_NOTE, module_object, "PT_NOTE"); yr_set_integer(ELF_PT_SHLIB, module_object, "PT_SHLIB"); yr_set_integer(ELF_PT_PHDR, module_object, "PT_PHDR"); yr_set_integer(ELF_PT_TLS, module_object, "PT_TLS"); yr_set_integer(ELF_PT_GNU_EH_FRAME, module_object, "PT_GNU_EH_FRAME"); yr_set_integer(ELF_PT_GNU_STACK, module_object, "PT_GNU_STACK"); yr_set_integer(ELF_DT_NULL, module_object, "DT_NULL"); yr_set_integer(ELF_DT_NEEDED, module_object, "DT_NEEDED"); yr_set_integer(ELF_DT_PLTRELSZ, module_object, "DT_PLTRELSZ"); yr_set_integer(ELF_DT_PLTGOT, module_object, "DT_PLTGOT"); yr_set_integer(ELF_DT_HASH, module_object, "DT_HASH"); yr_set_integer(ELF_DT_STRTAB, module_object, "DT_STRTAB"); yr_set_integer(ELF_DT_SYMTAB, module_object, "DT_SYMTAB"); yr_set_integer(ELF_DT_RELA, module_object, "DT_RELA"); yr_set_integer(ELF_DT_RELASZ, module_object, "DT_RELASZ"); yr_set_integer(ELF_DT_RELAENT, module_object, "DT_RELAENT"); yr_set_integer(ELF_DT_STRSZ, module_object, "DT_STRSZ"); yr_set_integer(ELF_DT_SYMENT, module_object, "DT_SYMENT"); yr_set_integer(ELF_DT_INIT, module_object, "DT_INIT"); yr_set_integer(ELF_DT_FINI, module_object, "DT_FINI"); yr_set_integer(ELF_DT_SONAME, module_object, "DT_SONAME"); yr_set_integer(ELF_DT_RPATH, module_object, "DT_RPATH"); yr_set_integer(ELF_DT_SYMBOLIC, module_object, "DT_SYMBOLIC"); yr_set_integer(ELF_DT_REL, module_object, "DT_REL"); yr_set_integer(ELF_DT_RELSZ, module_object, "DT_RELSZ"); yr_set_integer(ELF_DT_RELENT, module_object, "DT_RELENT"); yr_set_integer(ELF_DT_PLTREL, module_object, "DT_PLTREL"); yr_set_integer(ELF_DT_DEBUG, module_object, "DT_DEBUG"); yr_set_integer(ELF_DT_TEXTREL, module_object, "DT_TEXTREL"); yr_set_integer(ELF_DT_JMPREL, module_object, "DT_JMPREL"); yr_set_integer(ELF_DT_BIND_NOW, module_object, "DT_BIND_NOW"); yr_set_integer(ELF_DT_INIT_ARRAY, module_object, "DT_INIT_ARRAY"); yr_set_integer(ELF_DT_FINI_ARRAY, module_object, "DT_FINI_ARRAY"); yr_set_integer(ELF_DT_INIT_ARRAYSZ, module_object, "DT_INIT_ARRAYSZ"); yr_set_integer(ELF_DT_FINI_ARRAYSZ, module_object, "DT_FINI_ARRAYSZ"); yr_set_integer(ELF_DT_RUNPATH, module_object, "DT_RUNPATH"); yr_set_integer(ELF_DT_FLAGS, module_object, "DT_FLAGS"); yr_set_integer(ELF_DT_ENCODING, module_object, "DT_ENCODING"); yr_set_integer(ELF_STT_NOTYPE, module_object, "STT_NOTYPE"); yr_set_integer(ELF_STT_OBJECT, module_object, "STT_OBJECT"); yr_set_integer(ELF_STT_FUNC, module_object, "STT_FUNC"); yr_set_integer(ELF_STT_SECTION, module_object, "STT_SECTION"); yr_set_integer(ELF_STT_FILE, module_object, "STT_FILE"); yr_set_integer(ELF_STT_COMMON, module_object, "STT_COMMON"); yr_set_integer(ELF_STT_TLS, module_object, "STT_TLS"); yr_set_integer(ELF_STB_LOCAL, module_object, "STB_LOCAL"); yr_set_integer(ELF_STB_GLOBAL, module_object, "STB_GLOBAL"); yr_set_integer(ELF_STB_WEAK, module_object, "STB_WEAK"); yr_set_integer(ELF_PF_X, module_object, "PF_X"); yr_set_integer(ELF_PF_W, module_object, "PF_W"); yr_set_integer(ELF_PF_R, module_object, "PF_R"); uint64_t parse_result = ERROR_SUCCESS; foreach_memory_block(iterator, block) { const uint8_t* block_data = yr_fetch_block_data(block); if (block_data == NULL) continue; ELF* elf = (ELF*) yr_calloc(1, sizeof(ELF)); if (elf == NULL) return ERROR_INSUFFICIENT_MEMORY; module_object->data = elf; int class_data = get_elf_class_data(block_data, block->size); if (class_data == CLASS_DATA(ELF_CLASS_32, ELF_DATA_2LSB) && block->size > sizeof(elf32_header_t)) { elf_header32 = (elf32_header_t*) block_data; if (!(context->flags & SCAN_FLAGS_PROCESS_MEMORY) || yr_le16toh(elf_header32->type) == ELF_ET_EXEC) { parse_result = parse_elf_header_32_le( elf, elf_header32, block->base, block->size, context->flags, module_object); break; } } else if ( class_data == CLASS_DATA(ELF_CLASS_32, ELF_DATA_2MSB) && block->size > sizeof(elf32_header_t)) { elf_header32 = (elf32_header_t*) block_data; if (!(context->flags & SCAN_FLAGS_PROCESS_MEMORY) || yr_be16toh(elf_header32->type) == ELF_ET_EXEC) { parse_result = parse_elf_header_32_be( elf, elf_header32, block->base, block->size, context->flags, module_object); break; } } else if ( class_data == CLASS_DATA(ELF_CLASS_64, ELF_DATA_2LSB) && block->size > sizeof(elf64_header_t)) { elf_header64 = (elf64_header_t*) block_data; if (!(context->flags & SCAN_FLAGS_PROCESS_MEMORY) || yr_le16toh(elf_header64->type) == ELF_ET_EXEC) { parse_result = parse_elf_header_64_le( elf, elf_header64, block->base, block->size, context->flags, module_object); break; } } else if ( class_data == CLASS_DATA(ELF_CLASS_64, ELF_DATA_2MSB) && block->size > sizeof(elf64_header_t)) { elf_header64 = (elf64_header_t*) block_data; if (!(context->flags & SCAN_FLAGS_PROCESS_MEMORY) || yr_be16toh(elf_header64->type) == ELF_ET_EXEC) { parse_result = parse_elf_header_64_be( elf, elf_header64, block->base, block->size, context->flags, module_object); break; } } } return parse_result; } int module_unload(YR_OBJECT* module_object) { ELF* elf = (ELF*) module_object->data; if (elf == NULL) return ERROR_SUCCESS; if (elf->symtab != NULL) { ELF_SYMBOL *act = NULL, *next = NULL; for (act = elf->symtab->symbols; act != NULL; act = next) { next = act->next; if (act->name != NULL) yr_free(act->name); yr_free(act); } yr_free(elf->symtab); } if (elf->dynsym != NULL) { ELF_SYMBOL *act = NULL, *next = NULL; for (act = elf->dynsym->symbols; act != NULL; act = next) { next = act->next; if (act->name != NULL) yr_free(act->name); yr_free(act); } yr_free(elf->dynsym); } yr_free(elf->telfhash); yr_free(elf->import_hash); yr_free(elf); module_object->data = NULL; return ERROR_SUCCESS; } yara-4.5.3/libyara/modules/hash/000077500000000000000000000000001501365277300165065ustar00rootroot00000000000000yara-4.5.3/libyara/modules/hash/hash.c000066400000000000000000000565311501365277300176070ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "../crypto.h" #define MODULE_NAME hash typedef struct _CACHE_KEY { int64_t offset; int64_t length; } CACHE_KEY; const uint32_t crc32_tab[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; static void digest_to_ascii( unsigned char* digest, char* digest_ascii, size_t digest_length) { size_t i; for (i = 0; i < digest_length; i++) sprintf(digest_ascii + (i * 2), "%02x", digest[i]); digest_ascii[digest_length * 2] = '\0'; } static char* get_from_cache( YR_OBJECT* module_object, const char* ns, int64_t offset, int64_t length) { CACHE_KEY key; YR_HASH_TABLE* hash_table = (YR_HASH_TABLE*) module_object->data; key.offset = offset; key.length = length; char* result = (char*) yr_hash_table_lookup_raw_key( hash_table, &key, sizeof(key), ns); YR_DEBUG_FPRINTF( 2, stderr, "- %s(offset=%" PRIi64 " length=%" PRIi64 ") {} = %p\n", __FUNCTION__, offset, length, result); return result; } static int add_to_cache( YR_OBJECT* module_object, const char* ns, int64_t offset, int64_t length, const char* digest) { CACHE_KEY key; YR_HASH_TABLE* hash_table = (YR_HASH_TABLE*) module_object->data; char* copy = yr_strdup(digest); key.offset = offset; key.length = length; if (copy == NULL) return ERROR_INSUFFICIENT_MEMORY; int result = yr_hash_table_add_raw_key( hash_table, &key, sizeof(key), ns, (void*) copy); YR_DEBUG_FPRINTF( 2, stderr, "- %s(offset=%" PRIi64 " length=%" PRIi64 " digest=%s) {} = %d\n", __FUNCTION__, offset, length, digest, result); return result; } define_function(string_md5) { unsigned char digest[YR_MD5_LEN]; char digest_ascii[YR_MD5_LEN * 2 + 1]; yr_md5_ctx md5_context; SIZED_STRING* s = sized_string_argument(1); yr_md5_init(&md5_context); yr_md5_update(&md5_context, s->c_string, s->length); yr_md5_final(digest, &md5_context); digest_to_ascii(digest, digest_ascii, YR_MD5_LEN); YR_DEBUG_FPRINTF( 2, stderr, "- %s() {} = 0x%s // s->length=%u\n", __FUNCTION__, digest_ascii, s->length); return_string(digest_ascii); } define_function(string_sha256) { unsigned char digest[YR_SHA256_LEN]; char digest_ascii[YR_SHA256_LEN * 2 + 1]; yr_sha256_ctx sha256_context; SIZED_STRING* s = sized_string_argument(1); yr_sha256_init(&sha256_context); yr_sha256_update(&sha256_context, s->c_string, s->length); yr_sha256_final(digest, &sha256_context); digest_to_ascii(digest, digest_ascii, YR_SHA256_LEN); YR_DEBUG_FPRINTF( 2, stderr, "- %s() {} = 0x%s // s->length=%u\n", __FUNCTION__, digest_ascii, s->length); return_string(digest_ascii); } define_function(string_sha1) { unsigned char digest[YR_SHA1_LEN]; char digest_ascii[YR_SHA1_LEN * 2 + 1]; yr_sha1_ctx sha_context; SIZED_STRING* s = sized_string_argument(1); yr_sha1_init(&sha_context); yr_sha1_update(&sha_context, s->c_string, s->length); yr_sha1_final(digest, &sha_context); digest_to_ascii(digest, digest_ascii, YR_SHA1_LEN); YR_DEBUG_FPRINTF( 2, stderr, "- %s() {} = 0x%s // s->length=%u\n", __FUNCTION__, digest_ascii, s->length); return_string(digest_ascii); } define_function(string_checksum32) { size_t i; SIZED_STRING* s = sized_string_argument(1); uint32_t checksum = 0; for (i = 0; i < s->length; i++) checksum += (uint8_t) (s->c_string[i]); YR_DEBUG_FPRINTF( 2, stderr, "- %s() {} = 0x%x // s->length=%u\n", __FUNCTION__, checksum, s->length); return_integer(checksum); } define_function(data_md5) { yr_md5_ctx md5_context; unsigned char digest[YR_MD5_LEN]; char digest_ascii[YR_MD5_LEN * 2 + 1]; char* cached_ascii_digest; bool past_first_block = false; YR_SCAN_CONTEXT* context = yr_scan_context(); YR_MEMORY_BLOCK* block = first_memory_block(context); YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; int64_t arg_offset = integer_argument(1); // offset where to start int64_t arg_length = integer_argument(2); // length of bytes we want hash on int64_t offset = arg_offset; int64_t length = arg_length; YR_DEBUG_FPRINTF( 2, stderr, "+ %s(offset=%" PRIi64 " length=%" PRIi64 ") {\n", __FUNCTION__, offset, length); if (block == NULL) { YR_DEBUG_FPRINTF( 2, stderr, "} // %s() = YR_UNDEFINED // block == NULL\n", __FUNCTION__); return_string(YR_UNDEFINED); } if (offset < 0 || length < 0 || offset < block->base) { YR_DEBUG_FPRINTF( 2, stderr, "} // %s() = YR_UNDEFINED // bad offset / length\n", __FUNCTION__); return_string(YR_UNDEFINED); } cached_ascii_digest = get_from_cache(yr_module(), "md5", arg_offset, arg_length); if (cached_ascii_digest != NULL) { YR_DEBUG_FPRINTF( 2, stderr, "} // %s() = %s (cached)\n", __FUNCTION__, cached_ascii_digest); return_string(cached_ascii_digest); } yr_md5_init(&md5_context); foreach_memory_block(iterator, block) { // if desired block within current block if (offset >= block->base && offset < block->base + block->size) { const uint8_t* block_data = yr_fetch_block_data(block); if (block_data != NULL) { size_t data_offset = (size_t) (offset - block->base); size_t data_len = (size_t) yr_min( length, (size_t) (block->size - data_offset)); offset += data_len; length -= data_len; yr_md5_update(&md5_context, block_data + data_offset, data_len); } past_first_block = true; } else if (past_first_block) { // If offset is not within current block and we already // past the first block then the we are trying to compute // the checksum over a range of non contiguous blocks. As // range contains gaps of undefined data the checksum is // undefined. YR_DEBUG_FPRINTF( 2, stderr, "} // %s() = YR_UNDEFINED // past_first_block\n", __FUNCTION__); yr_md5_final(digest, &md5_context); return_string(YR_UNDEFINED); } if (block->base + block->size >= offset + length) break; } yr_md5_final(digest, &md5_context); if (!past_first_block) { YR_DEBUG_FPRINTF( 2, stderr, "} // %s() = YR_UNDEFINED // !past_first_block\n", __FUNCTION__); return_string(YR_UNDEFINED); } digest_to_ascii(digest, digest_ascii, YR_MD5_LEN); FAIL_ON_ERROR( add_to_cache(yr_module(), "md5", arg_offset, arg_length, digest_ascii)); YR_DEBUG_FPRINTF(2, stderr, "} // %s() = 0x%s\n", __FUNCTION__, digest_ascii); return_string(digest_ascii); } define_function(data_sha1) { yr_sha1_ctx sha_context; unsigned char digest[YR_SHA1_LEN]; char digest_ascii[YR_SHA1_LEN * 2 + 1]; char* cached_ascii_digest; int past_first_block = false; int64_t arg_offset = integer_argument(1); // offset where to start int64_t arg_length = integer_argument(2); // length of bytes we want hash on int64_t offset = arg_offset; int64_t length = arg_length; YR_SCAN_CONTEXT* context = yr_scan_context(); YR_MEMORY_BLOCK* block = first_memory_block(context); YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; YR_DEBUG_FPRINTF( 2, stderr, "+ %s(offset=%" PRIi64 " length=%" PRIi64 ") {\n", __FUNCTION__, offset, length); if (block == NULL) { YR_DEBUG_FPRINTF( 2, stderr, "} // %s() = YR_UNDEFINED // block == NULL\n", __FUNCTION__); return_string(YR_UNDEFINED); } if (offset < 0 || length < 0 || offset < block->base) { YR_DEBUG_FPRINTF( 2, stderr, "} // %s() = YR_UNDEFINED // bad offset / length\n", __FUNCTION__); return_string(YR_UNDEFINED); } cached_ascii_digest = get_from_cache( yr_module(), "sha1", arg_offset, arg_length); if (cached_ascii_digest != NULL) { YR_DEBUG_FPRINTF( 2, stderr, "} // %s() = %s (cached)\n", __FUNCTION__, cached_ascii_digest); return_string(cached_ascii_digest); } yr_sha1_init(&sha_context); foreach_memory_block(iterator, block) { // if desired block within current block if (offset >= block->base && offset < block->base + block->size) { const uint8_t* block_data = yr_fetch_block_data(block); if (block_data != NULL) { size_t data_offset = (size_t) (offset - block->base); size_t data_len = (size_t) yr_min( length, (size_t) block->size - data_offset); offset += data_len; length -= data_len; yr_sha1_update(&sha_context, block_data + data_offset, data_len); } past_first_block = true; } else if (past_first_block) { // If offset is not within current block and we already // past the first block then the we are trying to compute // the checksum over a range of non contiguous blocks. As // range contains gaps of undefined data the checksum is // undefined. YR_DEBUG_FPRINTF( 2, stderr, "} // %s() = YR_UNDEFINED // past_first_block\n", __FUNCTION__); yr_sha1_final(digest, &sha_context); return_string(YR_UNDEFINED); } if (block->base + block->size >= offset + length) break; } yr_sha1_final(digest, &sha_context); if (!past_first_block) { YR_DEBUG_FPRINTF( 2, stderr, "} // %s() = YR_UNDEFINED // !past_first_block\n", __FUNCTION__); return_string(YR_UNDEFINED); } digest_to_ascii(digest, digest_ascii, YR_SHA1_LEN); FAIL_ON_ERROR( add_to_cache(yr_module(), "sha1", arg_offset, arg_length, digest_ascii)); YR_DEBUG_FPRINTF(2, stderr, "} // %s() = 0x%s\n", __FUNCTION__, digest_ascii); return_string(digest_ascii); } define_function(data_sha256) { yr_sha256_ctx sha256_context; unsigned char digest[YR_SHA256_LEN]; char digest_ascii[YR_SHA256_LEN * 2 + 1]; char* cached_ascii_digest; int past_first_block = false; int64_t arg_offset = integer_argument(1); // offset where to start int64_t arg_length = integer_argument(2); // length of bytes we want hash on int64_t offset = arg_offset; int64_t length = arg_length; YR_SCAN_CONTEXT* context = yr_scan_context(); YR_MEMORY_BLOCK* block = first_memory_block(context); YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; YR_DEBUG_FPRINTF( 2, stderr, "+ %s(offset=%" PRIi64 " length=%" PRIi64 ") {\n", __FUNCTION__, offset, length); if (block == NULL) { YR_DEBUG_FPRINTF( 2, stderr, "} // %s() = YR_UNDEFINED // block == NULL\n", __FUNCTION__); return_string(YR_UNDEFINED); } if (offset < 0 || length < 0 || offset < block->base) { YR_DEBUG_FPRINTF( 2, stderr, "} // %s() = YR_UNDEFINED // bad offset / length\n", __FUNCTION__); return_string(YR_UNDEFINED); } cached_ascii_digest = get_from_cache( yr_module(), "sha256", arg_offset, arg_length); if (cached_ascii_digest != NULL) { YR_DEBUG_FPRINTF( 2, stderr, "} // %s() = %s (cached)\n", __FUNCTION__, cached_ascii_digest); return_string(cached_ascii_digest); } yr_sha256_init(&sha256_context); foreach_memory_block(iterator, block) { // if desired block within current block if (offset >= block->base && offset < block->base + block->size) { const uint8_t* block_data = yr_fetch_block_data(block); if (block_data != NULL) { size_t data_offset = (size_t) (offset - block->base); size_t data_len = (size_t) yr_min(length, block->size - data_offset); offset += data_len; length -= data_len; yr_sha256_update(&sha256_context, block_data + data_offset, data_len); } past_first_block = true; } else if (past_first_block) { // If offset is not within current block and we already // past the first block then the we are trying to compute // the checksum over a range of non contiguous blocks. As // range contains gaps of undefined data the checksum is // undefined. YR_DEBUG_FPRINTF( 2, stderr, "} // %s() = YR_UNDEFINED // past_first_block\n", __FUNCTION__); yr_sha256_final(digest, &sha256_context); return_string(YR_UNDEFINED); } if (block->base + block->size >= offset + length) break; } yr_sha256_final(digest, &sha256_context); if (!past_first_block) { YR_DEBUG_FPRINTF( 2, stderr, "} // %s() = YR_UNDEFINED // !past_first_block\n", __FUNCTION__); return_string(YR_UNDEFINED); } digest_to_ascii(digest, digest_ascii, YR_SHA256_LEN); FAIL_ON_ERROR( add_to_cache(yr_module(), "sha256", arg_offset, arg_length, digest_ascii)); YR_DEBUG_FPRINTF(2, stderr, "} // %s() = 0x%s\n", __FUNCTION__, digest_ascii); return_string(digest_ascii); } define_function(data_checksum32) { int64_t offset = integer_argument(1); // offset where to start int64_t length = integer_argument(2); // length of bytes we want hash on YR_DEBUG_FPRINTF( 2, stderr, "+ %s(offset=%" PRIi64 " length=%" PRIi64 ") {\n", __FUNCTION__, offset, length); YR_SCAN_CONTEXT* context = yr_scan_context(); YR_MEMORY_BLOCK* block = first_memory_block(context); YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; uint32_t checksum = 0; int past_first_block = false; if (block == NULL) return_integer(YR_UNDEFINED); if (offset < 0 || length < 0 || offset < block->base) return_integer(YR_UNDEFINED); foreach_memory_block(iterator, block) { if (offset >= block->base && offset < block->base + block->size) { const uint8_t* block_data = yr_fetch_block_data(block); if (block_data != NULL) { size_t i; size_t data_offset = (size_t) (offset - block->base); size_t data_len = (size_t) yr_min(length, block->size - data_offset); offset += data_len; length -= data_len; for (i = 0; i < data_len; i++) checksum += *(block_data + data_offset + i); } past_first_block = true; } else if (past_first_block) { // If offset is not within current block and we already // past the first block then the we are trying to compute // the checksum over a range of non contiguous blocks. As // range contains gaps of undefined data the checksum is // undefined. return_integer(YR_UNDEFINED); } if (block->base + block->size >= offset + length) break; } if (!past_first_block) return_integer(YR_UNDEFINED); YR_DEBUG_FPRINTF(2, stderr, "} // %s() = 0x%x\n", __FUNCTION__, checksum); return_integer(checksum); } define_function(string_crc32) { size_t i; SIZED_STRING* s = sized_string_argument(1); uint32_t checksum = 0xFFFFFFFF; for (i = 0; i < s->length; i++) checksum = crc32_tab[(checksum ^ (uint8_t) s->c_string[i]) & 0xFF] ^ (checksum >> 8); YR_DEBUG_FPRINTF( 2, stderr, "- %s() {} = 0x%x // s->length=%u\n", __FUNCTION__, checksum ^ 0xFFFFFFFF, s->length); return_integer(checksum ^ 0xFFFFFFFF); } define_function(data_crc32) { int64_t offset = integer_argument(1); // offset where to start int64_t length = integer_argument(2); // length of bytes we want hash on uint32_t checksum = 0xFFFFFFFF; YR_SCAN_CONTEXT* context = yr_scan_context(); YR_MEMORY_BLOCK* block = first_memory_block(context); YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; YR_DEBUG_FPRINTF( 2, stderr, "+ %s(offset=%" PRIi64 " length=%" PRIi64 ") {\n", __FUNCTION__, offset, length); int past_first_block = false; if (block == NULL) return_integer(YR_UNDEFINED); if (offset < 0 || length < 0 || offset < block->base) return_integer(YR_UNDEFINED); foreach_memory_block(iterator, block) { if (offset >= block->base && offset < block->base + block->size) { const uint8_t* block_data = yr_fetch_block_data(block); if (block_data != NULL) { size_t i; size_t data_offset = (size_t) (offset - block->base); size_t data_len = (size_t) yr_min(length, block->size - data_offset); offset += data_len; length -= data_len; for (i = 0; i < data_len; i++) checksum = crc32_tab[(checksum ^ *(block_data + data_offset + i)) & 0xFF] ^ (checksum >> 8); } past_first_block = true; } else if (past_first_block) { // If offset is not within current block and we already // past the first block then the we are trying to compute // the checksum over a range of non contiguous blocks. As // range contains gaps of undefined data the checksum is // undefined. return_integer(YR_UNDEFINED); } if (block->base + block->size >= offset + length) break; } if (!past_first_block) return_integer(YR_UNDEFINED); YR_DEBUG_FPRINTF( 2, stderr, "} // %s() = 0x%x\n", __FUNCTION__, checksum ^ 0xFFFFFFFF); return_integer(checksum ^ 0xFFFFFFFF); } begin_declarations declare_function("md5", "ii", "s", data_md5); declare_function("md5", "s", "s", string_md5); declare_function("sha1", "ii", "s", data_sha1); declare_function("sha1", "s", "s", string_sha1); declare_function("sha256", "ii", "s", data_sha256); declare_function("sha256", "s", "s", string_sha256); declare_function("checksum32", "ii", "i", data_checksum32); declare_function("checksum32", "s", "i", string_checksum32); declare_function("crc32", "ii", "i", data_crc32); declare_function("crc32", "s", "i", string_crc32); end_declarations int module_initialize(YR_MODULE* module) { YR_DEBUG_FPRINTF(2, stderr, "- %s() {}\n", __FUNCTION__); return ERROR_SUCCESS; } int module_finalize(YR_MODULE* module) { YR_DEBUG_FPRINTF(2, stderr, "- %s() {}\n", __FUNCTION__); return ERROR_SUCCESS; } int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { YR_DEBUG_FPRINTF(2, stderr, "- %s() {}\n", __FUNCTION__); YR_HASH_TABLE* hash_table; FAIL_ON_ERROR(yr_hash_table_create(17, &hash_table)); module_object->data = hash_table; return ERROR_SUCCESS; } int module_unload(YR_OBJECT* module_object) { YR_DEBUG_FPRINTF(2, stderr, "- %s() {}\n", __FUNCTION__); YR_HASH_TABLE* hash_table = (YR_HASH_TABLE*) module_object->data; if (hash_table != NULL) yr_hash_table_destroy(hash_table, (YR_HASH_TABLE_FREE_VALUE_FUNC) yr_free); return ERROR_SUCCESS; } yara-4.5.3/libyara/modules/macho/000077500000000000000000000000001501365277300166525ustar00rootroot00000000000000yara-4.5.3/libyara/modules/macho/macho.c000066400000000000000000001332131501365277300201100ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #define MODULE_NAME macho // Check for Mach-O binary magic constant. int is_macho_file_block(const uint32_t* magic) { return *magic == MH_MAGIC || *magic == MH_CIGAM || *magic == MH_MAGIC_64 || *magic == MH_CIGAM_64; } // Check if file is for 32-bit architecture. int macho_is_32(uint32_t magic) { return magic == MH_MAGIC || magic == MH_CIGAM; } // Check for Mach-O fat binary magic constant. int is_fat_macho_file_block(const uint32_t* magic) { return *magic == FAT_MAGIC || *magic == FAT_CIGAM || *magic == FAT_MAGIC_64 || *magic == FAT_CIGAM_64; } // Check if file is 32-bit fat file. int macho_fat_is_32(const uint32_t* magic) { return yr_be32toh(*magic) == FAT_MAGIC; } static int should_swap_bytes(const uint32_t magic) { // In big-endian platforms byte swapping is needed for little-endian files // but in little-endian platforms the files that need swapping are the // the big-endian ones. #if defined(WORDS_BIGENDIAN) return magic == MH_CIGAM || magic == MH_CIGAM_64 || magic == FAT_CIGAM || magic == FAT_CIGAM_64; #else return magic == MH_MAGIC || magic == MH_MAGIC_64 || magic == FAT_MAGIC || magic == FAT_MAGIC_64; #endif } static void swap_mach_header(yr_mach_header_64_t* mh) { // Don't swap the magic number so we can tell if swapping is needed mh->cputype = yr_bswap32(mh->cputype); mh->cpusubtype = yr_bswap32(mh->cpusubtype); mh->filetype = yr_bswap32(mh->filetype); mh->ncmds = yr_bswap32(mh->ncmds); mh->sizeofcmds = yr_bswap32(mh->sizeofcmds); mh->flags = yr_bswap32(mh->flags); if (!macho_is_32(mh->magic)) mh->reserved = yr_bswap32(mh->reserved); } static void swap_load_command(yr_load_command_t* lc) { lc->cmd = yr_bswap32(lc->cmd); lc->cmdsize = yr_bswap32(lc->cmdsize); } static void swap_segment_command(yr_segment_command_32_t* sg) { sg->cmd = yr_bswap32(sg->cmd); sg->cmdsize = yr_bswap32(sg->cmdsize); sg->vmaddr = yr_bswap32(sg->vmaddr); sg->vmsize = yr_bswap32(sg->vmsize); sg->fileoff = yr_bswap32(sg->fileoff); sg->filesize = yr_bswap32(sg->filesize); sg->maxprot = yr_bswap32(sg->maxprot); sg->initprot = yr_bswap32(sg->initprot); sg->nsects = yr_bswap32(sg->nsects); sg->flags = yr_bswap32(sg->flags); } static void swap_segment_command_64(yr_segment_command_64_t* sg) { sg->cmd = yr_bswap32(sg->cmd); sg->cmdsize = yr_bswap32(sg->cmdsize); sg->vmaddr = yr_bswap64(sg->vmaddr); sg->vmsize = yr_bswap64(sg->vmsize); sg->fileoff = yr_bswap64(sg->fileoff); sg->filesize = yr_bswap64(sg->filesize); sg->maxprot = yr_bswap32(sg->maxprot); sg->initprot = yr_bswap32(sg->initprot); sg->nsects = yr_bswap32(sg->nsects); sg->flags = yr_bswap32(sg->flags); } static void swap_section(yr_section_32_t* sec) { sec->addr = yr_bswap32(sec->addr); sec->size = yr_bswap32(sec->size); sec->offset = yr_bswap32(sec->offset); sec->align = yr_bswap32(sec->align); sec->reloff = yr_bswap32(sec->reloff); sec->nreloc = yr_bswap32(sec->nreloc); sec->flags = yr_bswap32(sec->flags); sec->reserved1 = yr_bswap32(sec->reserved1); sec->reserved2 = yr_bswap32(sec->reserved2); } static void swap_section_64(yr_section_64_t* sec) { sec->addr = yr_bswap64(sec->addr); sec->size = yr_bswap64(sec->size); sec->offset = yr_bswap32(sec->offset); sec->align = yr_bswap32(sec->align); sec->reloff = yr_bswap32(sec->reloff); sec->nreloc = yr_bswap32(sec->nreloc); sec->flags = yr_bswap32(sec->flags); sec->reserved1 = yr_bswap32(sec->reserved1); sec->reserved2 = yr_bswap32(sec->reserved2); sec->reserved3 = yr_bswap32(sec->reserved3); } static void swap_entry_point_command(yr_entry_point_command_t* ep_command) { ep_command->cmd = yr_bswap32(ep_command->cmd); ep_command->cmdsize = yr_bswap32(ep_command->cmdsize); ep_command->entryoff = yr_bswap64(ep_command->entryoff); ep_command->stacksize = yr_bswap64(ep_command->stacksize); } // Convert virtual address to file offset. Segments have to be already loaded. bool macho_rva_to_offset(uint64_t address, uint64_t* result, YR_OBJECT* object) { uint64_t segment_count = yr_get_integer(object, "number_of_segments"); for (int i = 0; i < segment_count; i++) { uint64_t start = yr_get_integer(object, "segments[%i].vmaddr", i); uint64_t end = start + yr_get_integer(object, "segments[%i].vmsize", i); if (address >= start && address < end) { uint64_t fileoff = yr_get_integer(object, "segments[%i].fileoff", i); *result = fileoff + (address - start); return true; } } return false; } // Convert file offset to virtual address. Segments have to be already loaded. int macho_offset_to_rva(uint64_t offset, uint64_t* result, YR_OBJECT* object) { uint64_t segment_count = yr_get_integer(object, "number_of_segments"); for (int i = 0; i < segment_count; i++) { uint64_t start = yr_get_integer(object, "segments[%i].fileoff", i); uint64_t end = start + yr_get_integer(object, "segments[%i].fsize", i); if (offset >= start && offset < end) { uint64_t vmaddr = yr_get_integer(object, "segments[%i].vmaddr", i); *result = vmaddr + (offset - start); return true; } } return false; } // Get entry point address from LC_UNIXTHREAD load command. void macho_handle_unixthread( const uint8_t* data, size_t size, uint64_t base_address, YR_OBJECT* object, YR_SCAN_CONTEXT* context) { int should_swap = should_swap_bytes(yr_get_integer(object, "magic")); bool is64 = false; if (size < sizeof(yr_thread_command_t)) return; // command_size is the size indicated in yr_thread_command_t structure, but // limited to the data's size because we can't rely on the structure having // a valid size. uint32_t command_size = yr_min(size, ((yr_thread_command_t*) data)->cmdsize); // command_size should be at least the size of yr_thread_command_t. if (command_size < sizeof(yr_thread_command_t)) return; // command_size includes the size of yr_thread_command_t and the thread // state structure that follows, let's compute the size of the thread state // structure. size_t thread_state_size = command_size - sizeof(yr_thread_command_t); // The structure that contains the thread state starts where // yr_thread_command_t ends. const void* thread_state = data + sizeof(yr_thread_command_t); uint64_t address = 0; switch (yr_get_integer(object, "cputype")) { case CPU_TYPE_MC680X0: { if (thread_state_size < sizeof(yr_m68k_thread_state_t)) return; address = ((yr_m68k_thread_state_t*) thread_state)->pc; break; } case CPU_TYPE_MC88000: { if (thread_state_size < sizeof(yr_m88k_thread_state_t)) return; address = ((yr_m88k_thread_state_t*) thread_state)->xip; break; } case CPU_TYPE_SPARC: { if (thread_state_size < sizeof(yr_sparc_thread_state_t)) return; address = ((yr_sparc_thread_state_t*) thread_state)->pc; break; } case CPU_TYPE_POWERPC: { if (thread_state_size < sizeof(yr_ppc_thread_state_t)) return; address = ((yr_ppc_thread_state_t*) thread_state)->srr0; break; } case CPU_TYPE_X86: { if (thread_state_size < sizeof(yr_x86_thread_state_t)) return; address = ((yr_x86_thread_state_t*) thread_state)->eip; break; } case CPU_TYPE_ARM: { if (thread_state_size < sizeof(yr_arm_thread_state_t)) return; address = ((yr_arm_thread_state_t*) thread_state)->pc; break; } case CPU_TYPE_X86_64: { if (thread_state_size < sizeof(yr_x86_thread_state64_t)) return; address = ((yr_x86_thread_state64_t*) thread_state)->rip; is64 = true; break; } case CPU_TYPE_ARM64: { if (thread_state_size < sizeof(yr_arm_thread_state64_t)) return; address = ((yr_arm_thread_state64_t*) thread_state)->pc; is64 = true; break; } case CPU_TYPE_POWERPC64: { if (thread_state_size < sizeof(yr_ppc_thread_state64_t)) return; address = ((yr_ppc_thread_state64_t*) thread_state)->srr0; is64 = true; break; } default: return; } if (should_swap) { if (is64) address = yr_bswap64(address); else address = yr_bswap32(address); } if (context->flags & SCAN_FLAGS_PROCESS_MEMORY) { yr_set_integer(base_address + address, object, "entry_point"); } else { uint64_t offset = 0; if (macho_rva_to_offset(address, &offset, object)) { yr_set_integer(offset, object, "entry_point"); } } } // Get entry point offset and stack-size from LC_MAIN load command. void macho_handle_main( void* data, size_t size, YR_OBJECT* object, YR_SCAN_CONTEXT* context) { yr_entry_point_command_t ep_command; if (size < sizeof(yr_entry_point_command_t)) return; memcpy(&ep_command, data, sizeof(yr_entry_point_command_t)); if (should_swap_bytes(yr_get_integer(object, "magic"))) swap_entry_point_command(&ep_command); if (context->flags & SCAN_FLAGS_PROCESS_MEMORY) { uint64_t address = 0; if (macho_offset_to_rva(ep_command.entryoff, &address, object)) { yr_set_integer(address, object, "entry_point"); } } else { yr_set_integer(ep_command.entryoff, object, "entry_point"); } yr_set_integer(ep_command.stacksize, object, "stack_size"); } // Load segment and its sections. void macho_handle_segment( const uint8_t* data, size_t size, const unsigned i, YR_OBJECT* object) { if (size < sizeof(yr_segment_command_32_t)) return; yr_segment_command_32_t sg; memcpy(&sg, data, sizeof(yr_segment_command_32_t)); int should_swap = should_swap_bytes(yr_get_integer(object, "magic")); if (should_swap) swap_segment_command(&sg); yr_set_sized_string( sg.segname, strnlen(sg.segname, 16), object, "segments[%i].segname", i); yr_set_integer(sg.vmaddr, object, "segments[%i].vmaddr", i); yr_set_integer(sg.vmsize, object, "segments[%i].vmsize", i); yr_set_integer(sg.fileoff, object, "segments[%i].fileoff", i); yr_set_integer(sg.filesize, object, "segments[%i].fsize", i); yr_set_integer(sg.maxprot, object, "segments[%i].maxprot", i); yr_set_integer(sg.initprot, object, "segments[%i].initprot", i); yr_set_integer(sg.nsects, object, "segments[%i].nsects", i); yr_set_integer(sg.flags, object, "segments[%i].flags", i); uint64_t parsed_size = sizeof(yr_segment_command_32_t); // The array of yr_section_32_t starts where yr_segment_command_32_t ends. yr_section_32_t* sections = (yr_section_32_t*) (data + sizeof(yr_segment_command_32_t)); for (unsigned j = 0; j < sg.nsects; ++j) { yr_section_32_t sec; parsed_size += sizeof(yr_section_32_t); if (sg.cmdsize < parsed_size) break; memcpy(&sec, §ions[j], sizeof(yr_section_32_t)); if (should_swap) swap_section(&sec); yr_set_sized_string( sec.segname, strnlen(sec.segname, 16), object, "segments[%i].sections[%i].segname", i, j); yr_set_sized_string( sec.sectname, strnlen(sec.sectname, 16), object, "segments[%i].sections[%i].sectname", i, j); yr_set_integer(sec.addr, object, "segments[%i].sections[%i].addr", i, j); yr_set_integer(sec.size, object, "segments[%i].sections[%i].size", i, j); yr_set_integer( sec.offset, object, "segments[%i].sections[%i].offset", i, j); yr_set_integer(sec.align, object, "segments[%i].sections[%i].align", i, j); yr_set_integer( sec.reloff, object, "segments[%i].sections[%i].reloff", i, j); yr_set_integer( sec.nreloc, object, "segments[%i].sections[%i].nreloc", i, j); yr_set_integer(sec.flags, object, "segments[%i].sections[%i].flags", i, j); yr_set_integer( sec.reserved1, object, "segments[%i].sections[%i].reserved1", i, j); yr_set_integer( sec.reserved2, object, "segments[%i].sections[%i].reserved2", i, j); } } void macho_handle_segment_64( const uint8_t* data, size_t size, const unsigned i, YR_OBJECT* object) { if (size < sizeof(yr_segment_command_64_t)) return; yr_segment_command_64_t sg; memcpy(&sg, data, sizeof(yr_segment_command_64_t)); int should_swap = should_swap_bytes(yr_get_integer(object, "magic")); if (should_swap) swap_segment_command_64(&sg); yr_set_sized_string( sg.segname, strnlen(sg.segname, 16), object, "segments[%i].segname", i); yr_set_integer(sg.vmaddr, object, "segments[%i].vmaddr", i); yr_set_integer(sg.vmsize, object, "segments[%i].vmsize", i); yr_set_integer(sg.fileoff, object, "segments[%i].fileoff", i); yr_set_integer(sg.filesize, object, "segments[%i].fsize", i); yr_set_integer(sg.maxprot, object, "segments[%i].maxprot", i); yr_set_integer(sg.initprot, object, "segments[%i].initprot", i); yr_set_integer(sg.nsects, object, "segments[%i].nsects", i); yr_set_integer(sg.flags, object, "segments[%i].flags", i); uint64_t parsed_size = sizeof(yr_segment_command_64_t); yr_section_64_t sec; for (unsigned j = 0; j < sg.nsects; ++j) { parsed_size += sizeof(yr_section_64_t); if (sg.cmdsize < parsed_size) break; memcpy( &sec, data + sizeof(yr_segment_command_64_t) + (j * sizeof(yr_section_64_t)), sizeof(yr_section_64_t)); if (should_swap) swap_section_64(&sec); yr_set_sized_string( sec.segname, strnlen(sec.segname, 16), object, "segments[%i].sections[%i].segname", i, j); yr_set_sized_string( sec.sectname, strnlen(sec.sectname, 16), object, "segments[%i].sections[%i].sectname", i, j); yr_set_integer(sec.addr, object, "segments[%i].sections[%i].addr", i, j); yr_set_integer(sec.size, object, "segments[%i].sections[%i].size", i, j); yr_set_integer( sec.offset, object, "segments[%i].sections[%i].offset", i, j); yr_set_integer(sec.align, object, "segments[%i].sections[%i].align", i, j); yr_set_integer( sec.reloff, object, "segments[%i].sections[%i].reloff", i, j); yr_set_integer( sec.nreloc, object, "segments[%i].sections[%i].nreloc", i, j); yr_set_integer(sec.flags, object, "segments[%i].sections[%i].flags", i, j); yr_set_integer( sec.reserved1, object, "segments[%i].sections[%i].reserved1", i, j); yr_set_integer( sec.reserved2, object, "segments[%i].sections[%i].reserved2", i, j); yr_set_integer( sec.reserved3, object, "segments[%i].sections[%i].reserved3", i, j); } } // Parse Mach-O file. void macho_parse_file( const uint8_t* data, const uint64_t size, const uint64_t base_address, YR_OBJECT* object, YR_SCAN_CONTEXT* context) { // Size must be large enough the hold yr_mach_header_64_t, which is larger // than yr_mach_header_32_t. if (size < sizeof(yr_mach_header_64_t)) return; // yr_mach_header_64_t is used for storing the header for both for 32-bits // and 64-bits files. yr_mach_header_64_t is exactly like // yr_mach_header_32_t but with an extra "reserved" field at the end. yr_mach_header_64_t header; memcpy(&header, data, sizeof(yr_mach_header_64_t)); // The magic number is always handled as big-endian. If the magic bytes are // CA FE BA BE, then header.magic is 0xCAFEBABE. header.magic = yr_be32toh(header.magic); size_t header_size = (header.magic == MH_MAGIC || header.magic == MH_CIGAM) ? sizeof(yr_mach_header_32_t) : sizeof(yr_mach_header_64_t); int should_swap = should_swap_bytes(header.magic); if (should_swap) swap_mach_header(&header); yr_set_integer(header.magic, object, "magic"); yr_set_integer(header.cputype, object, "cputype"); yr_set_integer(header.cpusubtype, object, "cpusubtype"); yr_set_integer(header.filetype, object, "filetype"); yr_set_integer(header.ncmds, object, "ncmds"); yr_set_integer(header.sizeofcmds, object, "sizeofcmds"); yr_set_integer(header.flags, object, "flags"); // The "reserved" field exists only in 64 bits files. if (!macho_is_32(header.magic)) yr_set_integer(header.reserved, object, "reserved"); // The first command parsing pass handles only segments. uint64_t seg_count = 0; uint64_t parsed_size = header_size; uint8_t* command = (uint8_t*) (data + header_size); yr_load_command_t command_struct; for (unsigned i = 0; i < header.ncmds; i++) { if (data + size < command + sizeof(yr_load_command_t)) break; memcpy(&command_struct, command, sizeof(yr_load_command_t)); if (should_swap) swap_load_command(&command_struct); if (size - parsed_size < command_struct.cmdsize) break; if (command_struct.cmdsize < sizeof(yr_load_command_t)) break; switch (command_struct.cmd) { case LC_SEGMENT: macho_handle_segment(command, size - parsed_size, seg_count++, object); break; case LC_SEGMENT_64: macho_handle_segment_64(command, size - parsed_size, seg_count++, object); break; } command += command_struct.cmdsize; parsed_size += command_struct.cmdsize; } yr_set_integer(seg_count, object, "number_of_segments"); // The second command parsing pass handles others, who use segment count. parsed_size = header_size; command = (uint8_t*) (data + header_size); for (unsigned i = 0; i < header.ncmds; i++) { if (data + size < command + sizeof(yr_load_command_t)) break; memcpy(&command_struct, command, sizeof(yr_load_command_t)); if (should_swap) swap_load_command(&command_struct); if (size - parsed_size < command_struct.cmdsize) break; if (command_struct.cmdsize < sizeof(yr_load_command_t)) break; switch (command_struct.cmd) { case LC_UNIXTHREAD: macho_handle_unixthread( command, size - parsed_size, base_address, object, context); break; case LC_MAIN: macho_handle_main(command, size - parsed_size, object, context); break; } command += command_struct.cmdsize; parsed_size += command_struct.cmdsize; } } // Parse Mach-O fat file. void macho_load_fat_arch_header( const uint8_t* data, const uint64_t size, uint32_t num, yr_fat_arch_64_t* arch) { if (macho_fat_is_32((uint32_t*) data)) { yr_fat_arch_32_t* arch32 = (yr_fat_arch_32_t*) (data + sizeof(yr_fat_header_t) + (num * sizeof(yr_fat_arch_32_t))); arch->cputype = yr_be32toh(arch32->cputype); arch->cpusubtype = yr_be32toh(arch32->cpusubtype); arch->offset = yr_be32toh(arch32->offset); arch->size = yr_be32toh(arch32->size); arch->align = yr_be32toh(arch32->align); arch->reserved = 0; } else { yr_fat_arch_64_t* arch64 = (yr_fat_arch_64_t*) (data + sizeof(yr_fat_header_t) + (num * sizeof(yr_fat_arch_64_t))); arch->cputype = yr_be32toh(arch64->cputype); arch->cpusubtype = yr_be32toh(arch64->cpusubtype); arch->offset = yr_be64toh(arch64->offset); arch->size = yr_be64toh(arch64->size); arch->align = yr_be32toh(arch64->align); arch->reserved = yr_be32toh(arch64->reserved); } } void macho_parse_fat_file( const uint8_t* data, const uint64_t size, const uint64_t base_address, YR_OBJECT* object, YR_SCAN_CONTEXT* context) { size_t fat_arch_sz = sizeof(yr_fat_arch_64_t); if (macho_fat_is_32((uint32_t*) data)) fat_arch_sz = sizeof(yr_fat_arch_32_t); if (size < sizeof(yr_fat_header_t)) return; /* All data in Mach-O fat binary headers are in big-endian byte order. */ const yr_fat_header_t* header = (yr_fat_header_t*) data; yr_set_integer(yr_be32toh(header->magic), object, "fat_magic"); uint32_t count = yr_be32toh(header->nfat_arch); yr_set_integer(count, object, "nfat_arch"); if (size < sizeof(yr_fat_header_t) + count * fat_arch_sz) return; yr_fat_arch_64_t arch; for (uint32_t i = 0; i < count; i++) { macho_load_fat_arch_header(data, size, i, &arch); yr_set_integer(arch.cputype, object, "fat_arch[%i].cputype", i); yr_set_integer(arch.cpusubtype, object, "fat_arch[%i].cpusubtype", i); yr_set_integer(arch.offset, object, "fat_arch[%i].offset", i); yr_set_integer(arch.size, object, "fat_arch[%i].size", i); yr_set_integer(arch.align, object, "fat_arch[%i].align", i); yr_set_integer(arch.reserved, object, "fat_arch[%i].reserved", i); // Check for integer overflow. if (arch.offset + arch.size < arch.offset) continue; if (size < arch.offset + arch.size) continue; // Force 'file' array entry creation. yr_set_integer(YR_UNDEFINED, object, "file[%i].magic", i); // Get specific Mach-O file data. macho_parse_file( data + arch.offset, arch.size, base_address, yr_get_object(object, "file[%i]", i), context); } } // Sets all necessary Mach-O constants and definitions. void macho_set_definitions(YR_OBJECT* object) { // Magic constants yr_set_integer(MH_MAGIC, object, "MH_MAGIC"); yr_set_integer(MH_CIGAM, object, "MH_CIGAM"); yr_set_integer(MH_MAGIC_64, object, "MH_MAGIC_64"); yr_set_integer(MH_CIGAM_64, object, "MH_CIGAM_64"); // Fat magic constants yr_set_integer(FAT_MAGIC, object, "FAT_MAGIC"); yr_set_integer(FAT_CIGAM, object, "FAT_CIGAM"); yr_set_integer(FAT_MAGIC_64, object, "FAT_MAGIC_64"); yr_set_integer(FAT_CIGAM_64, object, "FAT_CIGAM_64"); // 64-bit masks yr_set_integer(CPU_ARCH_ABI64, object, "CPU_ARCH_ABI64"); yr_set_integer(CPU_SUBTYPE_LIB64, object, "CPU_SUBTYPE_LIB64"); // CPU types yr_set_integer(CPU_TYPE_MC680X0, object, "CPU_TYPE_MC680X0"); yr_set_integer(CPU_TYPE_X86, object, "CPU_TYPE_X86"); yr_set_integer(CPU_TYPE_X86, object, "CPU_TYPE_I386"); yr_set_integer(CPU_TYPE_X86_64, object, "CPU_TYPE_X86_64"); yr_set_integer(CPU_TYPE_MIPS, object, "CPU_TYPE_MIPS"); yr_set_integer(CPU_TYPE_MC98000, object, "CPU_TYPE_MC98000"); yr_set_integer(CPU_TYPE_ARM, object, "CPU_TYPE_ARM"); yr_set_integer(CPU_TYPE_ARM64, object, "CPU_TYPE_ARM64"); yr_set_integer(CPU_TYPE_MC88000, object, "CPU_TYPE_MC88000"); yr_set_integer(CPU_TYPE_SPARC, object, "CPU_TYPE_SPARC"); yr_set_integer(CPU_TYPE_POWERPC, object, "CPU_TYPE_POWERPC"); yr_set_integer(CPU_TYPE_POWERPC64, object, "CPU_TYPE_POWERPC64"); // CPU sub-types yr_set_integer( CPU_SUBTYPE_INTEL_MODEL_ALL, object, "CPU_SUBTYPE_INTEL_MODEL_ALL"); yr_set_integer(CPU_SUBTYPE_386, object, "CPU_SUBTYPE_386"); yr_set_integer(CPU_SUBTYPE_386, object, "CPU_SUBTYPE_I386_ALL"); yr_set_integer(CPU_SUBTYPE_386, object, "CPU_SUBTYPE_X86_64_ALL"); yr_set_integer(CPU_SUBTYPE_486, object, "CPU_SUBTYPE_486"); yr_set_integer(CPU_SUBTYPE_486SX, object, "CPU_SUBTYPE_486SX"); yr_set_integer(CPU_SUBTYPE_586, object, "CPU_SUBTYPE_586"); yr_set_integer(CPU_SUBTYPE_PENT, object, "CPU_SUBTYPE_PENT"); yr_set_integer(CPU_SUBTYPE_PENTPRO, object, "CPU_SUBTYPE_PENTPRO"); yr_set_integer(CPU_SUBTYPE_PENTII_M3, object, "CPU_SUBTYPE_PENTII_M3"); yr_set_integer(CPU_SUBTYPE_PENTII_M5, object, "CPU_SUBTYPE_PENTII_M5"); yr_set_integer(CPU_SUBTYPE_CELERON, object, "CPU_SUBTYPE_CELERON"); yr_set_integer( CPU_SUBTYPE_CELERON_MOBILE, object, "CPU_SUBTYPE_CELERON_MOBILE"); yr_set_integer(CPU_SUBTYPE_PENTIUM_3, object, "CPU_SUBTYPE_PENTIUM_3"); yr_set_integer(CPU_SUBTYPE_PENTIUM_3_M, object, "CPU_SUBTYPE_PENTIUM_3_M"); yr_set_integer( CPU_SUBTYPE_PENTIUM_3_XEON, object, "CPU_SUBTYPE_PENTIUM_3_XEON"); yr_set_integer(CPU_SUBTYPE_PENTIUM_M, object, "CPU_SUBTYPE_PENTIUM_M"); yr_set_integer(CPU_SUBTYPE_PENTIUM_4, object, "CPU_SUBTYPE_PENTIUM_4"); yr_set_integer(CPU_SUBTYPE_PENTIUM_4_M, object, "CPU_SUBTYPE_PENTIUM_4_M"); yr_set_integer(CPU_SUBTYPE_ITANIUM, object, "CPU_SUBTYPE_ITANIUM"); yr_set_integer(CPU_SUBTYPE_ITANIUM_2, object, "CPU_SUBTYPE_ITANIUM_2"); yr_set_integer(CPU_SUBTYPE_XEON, object, "CPU_SUBTYPE_XEON"); yr_set_integer(CPU_SUBTYPE_XEON_MP, object, "CPU_SUBTYPE_XEON_MP"); yr_set_integer(CPU_SUBTYPE_ARM_ALL, object, "CPU_SUBTYPE_ARM_ALL"); yr_set_integer(CPU_SUBTYPE_ARM_V4T, object, "CPU_SUBTYPE_ARM_V4T"); yr_set_integer(CPU_SUBTYPE_ARM_V6, object, "CPU_SUBTYPE_ARM_V6"); yr_set_integer(CPU_SUBTYPE_ARM_V5, object, "CPU_SUBTYPE_ARM_V5"); yr_set_integer(CPU_SUBTYPE_ARM_V5TEJ, object, "CPU_SUBTYPE_ARM_V5TEJ"); yr_set_integer(CPU_SUBTYPE_ARM_XSCALE, object, "CPU_SUBTYPE_ARM_XSCALE"); yr_set_integer(CPU_SUBTYPE_ARM_V7, object, "CPU_SUBTYPE_ARM_V7"); yr_set_integer(CPU_SUBTYPE_ARM_V7F, object, "CPU_SUBTYPE_ARM_V7F"); yr_set_integer(CPU_SUBTYPE_ARM_V7S, object, "CPU_SUBTYPE_ARM_V7S"); yr_set_integer(CPU_SUBTYPE_ARM_V7K, object, "CPU_SUBTYPE_ARM_V7K"); yr_set_integer(CPU_SUBTYPE_ARM_V6M, object, "CPU_SUBTYPE_ARM_V6M"); yr_set_integer(CPU_SUBTYPE_ARM_V7M, object, "CPU_SUBTYPE_ARM_V7M"); yr_set_integer(CPU_SUBTYPE_ARM_V7EM, object, "CPU_SUBTYPE_ARM_V7EM"); yr_set_integer(CPU_SUBTYPE_ARM64_ALL, object, "CPU_SUBTYPE_ARM64_ALL"); yr_set_integer(CPU_SUBTYPE_SPARC_ALL, object, "CPU_SUBTYPE_SPARC_ALL"); yr_set_integer(CPU_SUBTYPE_POWERPC_ALL, object, "CPU_SUBTYPE_POWERPC_ALL"); yr_set_integer(CPU_SUBTYPE_MC980000_ALL, object, "CPU_SUBTYPE_MC980000_ALL"); yr_set_integer(CPU_SUBTYPE_POWERPC_601, object, "CPU_SUBTYPE_POWERPC_601"); yr_set_integer(CPU_SUBTYPE_MC98601, object, "CPU_SUBTYPE_MC98601"); yr_set_integer(CPU_SUBTYPE_POWERPC_602, object, "CPU_SUBTYPE_POWERPC_602"); yr_set_integer(CPU_SUBTYPE_POWERPC_603, object, "CPU_SUBTYPE_POWERPC_603"); yr_set_integer(CPU_SUBTYPE_POWERPC_603e, object, "CPU_SUBTYPE_POWERPC_603e"); yr_set_integer( CPU_SUBTYPE_POWERPC_603ev, object, "CPU_SUBTYPE_POWERPC_603ev"); yr_set_integer(CPU_SUBTYPE_POWERPC_604, object, "CPU_SUBTYPE_POWERPC_604"); yr_set_integer(CPU_SUBTYPE_POWERPC_604e, object, "CPU_SUBTYPE_POWERPC_604e"); yr_set_integer(CPU_SUBTYPE_POWERPC_620, object, "CPU_SUBTYPE_POWERPC_620"); yr_set_integer(CPU_SUBTYPE_POWERPC_750, object, "CPU_SUBTYPE_POWERPC_750"); yr_set_integer(CPU_SUBTYPE_POWERPC_7400, object, "CPU_SUBTYPE_POWERPC_7400"); yr_set_integer(CPU_SUBTYPE_POWERPC_7450, object, "CPU_SUBTYPE_POWERPC_7450"); yr_set_integer(CPU_SUBTYPE_POWERPC_970, object, "CPU_SUBTYPE_POWERPC_970"); // File types yr_set_integer(MH_OBJECT, object, "MH_OBJECT"); yr_set_integer(MH_EXECUTE, object, "MH_EXECUTE"); yr_set_integer(MH_FVMLIB, object, "MH_FVMLIB"); yr_set_integer(MH_CORE, object, "MH_CORE"); yr_set_integer(MH_PRELOAD, object, "MH_PRELOAD"); yr_set_integer(MH_DYLIB, object, "MH_DYLIB"); yr_set_integer(MH_DYLINKER, object, "MH_DYLINKER"); yr_set_integer(MH_BUNDLE, object, "MH_BUNDLE"); yr_set_integer(MH_DYLIB_STUB, object, "MH_DYLIB_STUB"); yr_set_integer(MH_DSYM, object, "MH_DSYM"); yr_set_integer(MH_KEXT_BUNDLE, object, "MH_KEXT_BUNDLE"); // Header flags yr_set_integer(MH_NOUNDEFS, object, "MH_NOUNDEFS"); yr_set_integer(MH_INCRLINK, object, "MH_INCRLINK"); yr_set_integer(MH_DYLDLINK, object, "MH_DYLDLINK"); yr_set_integer(MH_BINDATLOAD, object, "MH_BINDATLOAD"); yr_set_integer(MH_PREBOUND, object, "MH_PREBOUND"); yr_set_integer(MH_SPLIT_SEGS, object, "MH_SPLIT_SEGS"); yr_set_integer(MH_LAZY_INIT, object, "MH_LAZY_INIT"); yr_set_integer(MH_TWOLEVEL, object, "MH_TWOLEVEL"); yr_set_integer(MH_FORCE_FLAT, object, "MH_FORCE_FLAT"); yr_set_integer(MH_NOMULTIDEFS, object, "MH_NOMULTIDEFS"); yr_set_integer(MH_NOFIXPREBINDING, object, "MH_NOFIXPREBINDING"); yr_set_integer(MH_PREBINDABLE, object, "MH_PREBINDABLE"); yr_set_integer(MH_ALLMODSBOUND, object, "MH_ALLMODSBOUND"); yr_set_integer( MH_SUBSECTIONS_VIA_SYMBOLS, object, "MH_SUBSECTIONS_VIA_SYMBOLS"); yr_set_integer(MH_CANONICAL, object, "MH_CANONICAL"); yr_set_integer(MH_WEAK_DEFINES, object, "MH_WEAK_DEFINES"); yr_set_integer(MH_BINDS_TO_WEAK, object, "MH_BINDS_TO_WEAK"); yr_set_integer(MH_ALLOW_STACK_EXECUTION, object, "MH_ALLOW_STACK_EXECUTION"); yr_set_integer(MH_ROOT_SAFE, object, "MH_ROOT_SAFE"); yr_set_integer(MH_SETUID_SAFE, object, "MH_SETUID_SAFE"); yr_set_integer(MH_NO_REEXPORTED_DYLIBS, object, "MH_NO_REEXPORTED_DYLIBS"); yr_set_integer(MH_PIE, object, "MH_PIE"); yr_set_integer(MH_DEAD_STRIPPABLE_DYLIB, object, "MH_DEAD_STRIPPABLE_DYLIB"); yr_set_integer(MH_HAS_TLV_DESCRIPTORS, object, "MH_HAS_TLV_DESCRIPTORS"); yr_set_integer(MH_NO_HEAP_EXECUTION, object, "MH_NO_HEAP_EXECUTION"); yr_set_integer(MH_APP_EXTENSION_SAFE, object, "MH_APP_EXTENSION_SAFE"); // Segment flags masks yr_set_integer(SG_HIGHVM, object, "SG_HIGHVM"); yr_set_integer(SG_FVMLIB, object, "SG_FVMLIB"); yr_set_integer(SG_NORELOC, object, "SG_NORELOC"); yr_set_integer(SG_PROTECTED_VERSION_1, object, "SG_PROTECTED_VERSION_1"); // Section flags masks yr_set_integer(SECTION_TYPE, object, "SECTION_TYPE"); yr_set_integer(SECTION_ATTRIBUTES, object, "SECTION_ATTRIBUTES"); // Section types yr_set_integer(S_REGULAR, object, "S_REGULAR"); yr_set_integer(S_ZEROFILL, object, "S_ZEROFILL"); yr_set_integer(S_CSTRING_LITERALS, object, "S_CSTRING_LITERALS"); yr_set_integer(S_4BYTE_LITERALS, object, "S_4BYTE_LITERALS"); yr_set_integer(S_8BYTE_LITERALS, object, "S_8BYTE_LITERALS"); yr_set_integer( S_NON_LAZY_SYMBOL_POINTERS, object, "S_NON_LAZY_SYMBOL_POINTERS"); yr_set_integer(S_LAZY_SYMBOL_POINTERS, object, "S_LAZY_SYMBOL_POINTERS"); yr_set_integer(S_LITERAL_POINTERS, object, "S_LITERAL_POINTERS"); yr_set_integer(S_SYMBOL_STUBS, object, "S_SYMBOL_STUBS"); yr_set_integer(S_MOD_INIT_FUNC_POINTERS, object, "S_MOD_INIT_FUNC_POINTERS"); yr_set_integer(S_MOD_TERM_FUNC_POINTERS, object, "S_MOD_TERM_FUNC_POINTERS"); yr_set_integer(S_COALESCED, object, "S_COALESCED"); yr_set_integer(S_GB_ZEROFILL, object, "S_GB_ZEROFILL"); yr_set_integer(S_INTERPOSING, object, "S_INTERPOSING"); yr_set_integer(S_16BYTE_LITERALS, object, "S_16BYTE_LITERALS"); yr_set_integer(S_DTRACE_DOF, object, "S_DTRACE_DOF"); yr_set_integer( S_LAZY_DYLIB_SYMBOL_POINTERS, object, "S_LAZY_DYLIB_SYMBOL_POINTERS"); yr_set_integer(S_THREAD_LOCAL_REGULAR, object, "S_THREAD_LOCAL_REGULAR"); yr_set_integer(S_THREAD_LOCAL_ZEROFILL, object, "S_THREAD_LOCAL_ZEROFILL"); yr_set_integer(S_THREAD_LOCAL_VARIABLES, object, "S_THREAD_LOCAL_VARIABLES"); yr_set_integer( S_THREAD_LOCAL_VARIABLE_POINTERS, object, "S_THREAD_LOCAL_VARIABLE_POINTERS"); yr_set_integer( S_THREAD_LOCAL_INIT_FUNCTION_POINTERS, object, "S_THREAD_LOCAL_INIT_FUNCTION_POINTERS"); // Section attributes yr_set_integer(S_ATTR_PURE_INSTRUCTIONS, object, "S_ATTR_PURE_INSTRUCTIONS"); yr_set_integer(S_ATTR_NO_TOC, object, "S_ATTR_NO_TOC"); yr_set_integer(S_ATTR_STRIP_STATIC_SYMS, object, "S_ATTR_STRIP_STATIC_SYMS"); yr_set_integer(S_ATTR_NO_DEAD_STRIP, object, "S_ATTR_NO_DEAD_STRIP"); yr_set_integer(S_ATTR_LIVE_SUPPORT, object, "S_ATTR_LIVE_SUPPORT"); yr_set_integer( S_ATTR_SELF_MODIFYING_CODE, object, "S_ATTR_SELF_MODIFYING_CODE"); yr_set_integer(S_ATTR_DEBUG, object, "S_ATTR_DEBUG"); yr_set_integer(S_ATTR_SOME_INSTRUCTIONS, object, "S_ATTR_SOME_INSTRUCTIONS"); yr_set_integer(S_ATTR_EXT_RELOC, object, "S_ATTR_EXT_RELOC"); yr_set_integer(S_ATTR_LOC_RELOC, object, "S_ATTR_LOC_RELOC"); } // Get Mach-O file index in fat file by cputype field. define_function(file_index_type) { YR_OBJECT* module = yr_module(); int64_t type_arg = integer_argument(1); uint64_t nfat = yr_get_integer(module, "nfat_arch"); if (yr_is_undefined(module, "nfat_arch")) return_integer(YR_UNDEFINED); for (int i = 0; i < nfat; i++) { int64_t type = yr_get_integer(module, "file[%i].cputype", i); if (type == type_arg) { return_integer(i); } } return_integer(YR_UNDEFINED); } // Get Mach-O file index in fat file by cputype and cpusubtype fields. define_function(file_index_subtype) { YR_OBJECT* module = yr_module(); int64_t type_arg = integer_argument(1); int64_t subtype_arg = integer_argument(2); uint64_t nfat = yr_get_integer(module, "nfat_arch"); if (yr_is_undefined(module, "nfat_arch")) return_integer(YR_UNDEFINED); for (int i = 0; i < nfat; i++) { int64_t type = yr_get_integer(module, "file[%i].cputype", i); int64_t subtype = yr_get_integer(module, "file[%i].cpusubtype", i); if (type == type_arg && subtype == subtype_arg) { return_integer(i); } } return_integer(YR_UNDEFINED); } // Get real entry point offset for specific architecture in fat Mach-O. define_function(ep_for_arch_type) { YR_OBJECT* module = yr_module(); int64_t type_arg = integer_argument(1); uint64_t nfat = yr_get_integer(module, "nfat_arch"); if (yr_is_undefined(module, "nfat_arch")) return_integer(YR_UNDEFINED); for (int i = 0; i < nfat; i++) { int64_t type = yr_get_integer(module, "fat_arch[%i].cputype", i); if (type == type_arg) { uint64_t file_offset = yr_get_integer(module, "fat_arch[%i].offset", i); uint64_t entry_point = yr_get_integer(module, "file[%i].entry_point", i); return_integer(file_offset + entry_point); } } return_integer(YR_UNDEFINED); } // Get real entry point offset for specific architecture in fat Mach-O. define_function(ep_for_arch_subtype) { YR_OBJECT* module = yr_module(); int64_t type_arg = integer_argument(1); int64_t subtype_arg = integer_argument(2); uint64_t nfat = yr_get_integer(module, "nfat_arch"); if (yr_is_undefined(module, "nfat_arch")) return_integer(YR_UNDEFINED); for (int i = 0; i < nfat; i++) { int64_t type = yr_get_integer(module, "fat_arch[%i].cputype", i); int64_t subtype = yr_get_integer(module, "fat_arch[%i].cpusubtype", i); if (type == type_arg && subtype == subtype_arg) { uint64_t entry_point = yr_get_integer(module, "file[%i].entry_point", i); uint64_t file_offset = yr_get_integer(module, "fat_arch[%i].offset", i); if (entry_point == YR_UNDEFINED) { return_integer(YR_UNDEFINED); } else { return_integer(file_offset + entry_point); } } } return_integer(YR_UNDEFINED); } begin_declarations // Magic constants declare_integer("MH_MAGIC"); declare_integer("MH_CIGAM"); declare_integer("MH_MAGIC_64"); declare_integer("MH_CIGAM_64"); // Fat magic constants declare_integer("FAT_MAGIC"); declare_integer("FAT_CIGAM"); declare_integer("FAT_MAGIC_64"); declare_integer("FAT_CIGAM_64"); // 64-bit masks declare_integer("CPU_ARCH_ABI64"); declare_integer("CPU_SUBTYPE_LIB64"); // CPU types declare_integer("CPU_TYPE_MC680X0"); declare_integer("CPU_TYPE_X86"); declare_integer("CPU_TYPE_I386"); declare_integer("CPU_TYPE_X86_64"); declare_integer("CPU_TYPE_MIPS"); declare_integer("CPU_TYPE_MC98000"); declare_integer("CPU_TYPE_ARM"); declare_integer("CPU_TYPE_ARM64"); declare_integer("CPU_TYPE_MC88000"); declare_integer("CPU_TYPE_SPARC"); declare_integer("CPU_TYPE_POWERPC"); declare_integer("CPU_TYPE_POWERPC64"); // CPU sub-types declare_integer("CPU_SUBTYPE_INTEL_MODEL_ALL"); declare_integer("CPU_SUBTYPE_386"); declare_integer("CPU_SUBTYPE_I386_ALL"); declare_integer("CPU_SUBTYPE_X86_64_ALL"); declare_integer("CPU_SUBTYPE_486"); declare_integer("CPU_SUBTYPE_486SX"); declare_integer("CPU_SUBTYPE_586"); declare_integer("CPU_SUBTYPE_PENT"); declare_integer("CPU_SUBTYPE_PENTPRO"); declare_integer("CPU_SUBTYPE_PENTII_M3"); declare_integer("CPU_SUBTYPE_PENTII_M5"); declare_integer("CPU_SUBTYPE_CELERON"); declare_integer("CPU_SUBTYPE_CELERON_MOBILE"); declare_integer("CPU_SUBTYPE_PENTIUM_3"); declare_integer("CPU_SUBTYPE_PENTIUM_3_M"); declare_integer("CPU_SUBTYPE_PENTIUM_3_XEON"); declare_integer("CPU_SUBTYPE_PENTIUM_M"); declare_integer("CPU_SUBTYPE_PENTIUM_4"); declare_integer("CPU_SUBTYPE_PENTIUM_4_M"); declare_integer("CPU_SUBTYPE_ITANIUM"); declare_integer("CPU_SUBTYPE_ITANIUM_2"); declare_integer("CPU_SUBTYPE_XEON"); declare_integer("CPU_SUBTYPE_XEON_MP"); declare_integer("CPU_SUBTYPE_ARM_ALL"); declare_integer("CPU_SUBTYPE_ARM_V4T"); declare_integer("CPU_SUBTYPE_ARM_V6"); declare_integer("CPU_SUBTYPE_ARM_V5"); declare_integer("CPU_SUBTYPE_ARM_V5TEJ"); declare_integer("CPU_SUBTYPE_ARM_XSCALE"); declare_integer("CPU_SUBTYPE_ARM_V7"); declare_integer("CPU_SUBTYPE_ARM_V7F"); declare_integer("CPU_SUBTYPE_ARM_V7S"); declare_integer("CPU_SUBTYPE_ARM_V7K"); declare_integer("CPU_SUBTYPE_ARM_V6M"); declare_integer("CPU_SUBTYPE_ARM_V7M"); declare_integer("CPU_SUBTYPE_ARM_V7EM"); declare_integer("CPU_SUBTYPE_ARM64_ALL"); declare_integer("CPU_SUBTYPE_SPARC_ALL"); declare_integer("CPU_SUBTYPE_POWERPC_ALL"); declare_integer("CPU_SUBTYPE_MC980000_ALL"); declare_integer("CPU_SUBTYPE_POWERPC_601"); declare_integer("CPU_SUBTYPE_MC98601"); declare_integer("CPU_SUBTYPE_POWERPC_602"); declare_integer("CPU_SUBTYPE_POWERPC_603"); declare_integer("CPU_SUBTYPE_POWERPC_603e"); declare_integer("CPU_SUBTYPE_POWERPC_603ev"); declare_integer("CPU_SUBTYPE_POWERPC_604"); declare_integer("CPU_SUBTYPE_POWERPC_604e"); declare_integer("CPU_SUBTYPE_POWERPC_620"); declare_integer("CPU_SUBTYPE_POWERPC_750"); declare_integer("CPU_SUBTYPE_POWERPC_7400"); declare_integer("CPU_SUBTYPE_POWERPC_7450"); declare_integer("CPU_SUBTYPE_POWERPC_970"); // File types declare_integer("MH_OBJECT"); declare_integer("MH_EXECUTE"); declare_integer("MH_FVMLIB"); declare_integer("MH_CORE"); declare_integer("MH_PRELOAD"); declare_integer("MH_DYLIB"); declare_integer("MH_DYLINKER"); declare_integer("MH_BUNDLE"); declare_integer("MH_DYLIB_STUB"); declare_integer("MH_DSYM"); declare_integer("MH_KEXT_BUNDLE"); // Header flags declare_integer("MH_NOUNDEFS"); declare_integer("MH_INCRLINK"); declare_integer("MH_DYLDLINK"); declare_integer("MH_BINDATLOAD"); declare_integer("MH_PREBOUND"); declare_integer("MH_SPLIT_SEGS"); declare_integer("MH_LAZY_INIT"); declare_integer("MH_TWOLEVEL"); declare_integer("MH_FORCE_FLAT"); declare_integer("MH_NOMULTIDEFS"); declare_integer("MH_NOFIXPREBINDING"); declare_integer("MH_PREBINDABLE"); declare_integer("MH_ALLMODSBOUND"); declare_integer("MH_SUBSECTIONS_VIA_SYMBOLS"); declare_integer("MH_CANONICAL"); declare_integer("MH_WEAK_DEFINES"); declare_integer("MH_BINDS_TO_WEAK"); declare_integer("MH_ALLOW_STACK_EXECUTION"); declare_integer("MH_ROOT_SAFE"); declare_integer("MH_SETUID_SAFE"); declare_integer("MH_NO_REEXPORTED_DYLIBS"); declare_integer("MH_PIE"); declare_integer("MH_DEAD_STRIPPABLE_DYLIB"); declare_integer("MH_HAS_TLV_DESCRIPTORS"); declare_integer("MH_NO_HEAP_EXECUTION"); declare_integer("MH_APP_EXTENSION_SAFE"); // Segment flags declare_integer("SG_HIGHVM"); declare_integer("SG_FVMLIB"); declare_integer("SG_NORELOC"); declare_integer("SG_PROTECTED_VERSION_1"); // Section masks declare_integer("SECTION_TYPE"); declare_integer("SECTION_ATTRIBUTES"); // Section types declare_integer("S_REGULAR"); declare_integer("S_ZEROFILL"); declare_integer("S_CSTRING_LITERALS"); declare_integer("S_4BYTE_LITERALS"); declare_integer("S_8BYTE_LITERALS"); declare_integer("S_LITERAL_POINTERS"); declare_integer("S_NON_LAZY_SYMBOL_POINTERS"); declare_integer("S_LAZY_SYMBOL_POINTERS"); declare_integer("S_SYMBOL_STUBS"); declare_integer("S_MOD_INIT_FUNC_POINTERS"); declare_integer("S_MOD_TERM_FUNC_POINTERS"); declare_integer("S_COALESCED"); declare_integer("S_GB_ZEROFILL"); declare_integer("S_INTERPOSING"); declare_integer("S_16BYTE_LITERALS"); declare_integer("S_DTRACE_DOF"); declare_integer("S_LAZY_DYLIB_SYMBOL_POINTERS"); declare_integer("S_THREAD_LOCAL_REGULAR"); declare_integer("S_THREAD_LOCAL_ZEROFILL"); declare_integer("S_THREAD_LOCAL_VARIABLES"); declare_integer("S_THREAD_LOCAL_VARIABLE_POINTERS"); declare_integer("S_THREAD_LOCAL_INIT_FUNCTION_POINTERS"); // Section attributes declare_integer("S_ATTR_PURE_INSTRUCTIONS"); declare_integer("S_ATTR_NO_TOC"); declare_integer("S_ATTR_STRIP_STATIC_SYMS"); declare_integer("S_ATTR_NO_DEAD_STRIP"); declare_integer("S_ATTR_LIVE_SUPPORT"); declare_integer("S_ATTR_SELF_MODIFYING_CODE"); declare_integer("S_ATTR_DEBUG"); declare_integer("S_ATTR_SOME_INSTRUCTIONS"); declare_integer("S_ATTR_EXT_RELOC"); declare_integer("S_ATTR_LOC_RELOC"); // Header declare_integer("magic"); declare_integer("cputype"); declare_integer("cpusubtype"); declare_integer("filetype"); declare_integer("ncmds"); declare_integer("sizeofcmds"); declare_integer("flags"); declare_integer("reserved"); // Segments and nested sections declare_integer("number_of_segments"); begin_struct_array("segments") declare_string("segname"); declare_integer("vmaddr"); declare_integer("vmsize"); declare_integer("fileoff"); declare_integer("fsize"); declare_integer("maxprot"); declare_integer("initprot"); declare_integer("nsects"); declare_integer("flags"); begin_struct_array("sections") declare_string("sectname"); declare_string("segname"); declare_integer("addr"); declare_integer("size"); declare_integer("offset"); declare_integer("align"); declare_integer("reloff"); declare_integer("nreloc"); declare_integer("flags"); declare_integer("reserved1"); declare_integer("reserved2"); declare_integer("reserved3"); end_struct_array("sections"); end_struct_array("segments") // Entry point and stack size declare_integer("entry_point"); declare_integer("stack_size"); // Mach-O fat binary header declare_integer("fat_magic"); declare_integer("nfat_arch"); begin_struct_array("fat_arch") declare_integer("cputype"); declare_integer("cpusubtype"); declare_integer("offset"); declare_integer("size"); declare_integer("align"); end_struct_array("fat_arch") // Included Mach-O files (must be same as single file structure above) begin_struct_array("file") // Single file header declare_integer("magic"); declare_integer("cputype"); declare_integer("cpusubtype"); declare_integer("filetype"); declare_integer("ncmds"); declare_integer("sizeofcmds"); declare_integer("flags"); declare_integer("reserved"); // Segments and nested sections declare_integer("number_of_segments"); begin_struct_array("segments") declare_string("segname"); declare_integer("vmaddr"); declare_integer("vmsize"); declare_integer("fileoff"); declare_integer("fsize"); declare_integer("maxprot"); declare_integer("initprot"); declare_integer("nsects"); declare_integer("flags"); begin_struct_array("sections") declare_string("sectname"); declare_string("segname"); declare_integer("addr"); declare_integer("size"); declare_integer("offset"); declare_integer("align"); declare_integer("reloff"); declare_integer("nreloc"); declare_integer("flags"); declare_integer("reserved1"); declare_integer("reserved2"); declare_integer("reserved3"); end_struct_array("sections"); end_struct_array("segments") // Entry point and stack size declare_integer("entry_point"); declare_integer("stack_size"); end_struct_array("file"); // Mach-O fat binary helper functions declare_function("file_index_for_arch", "i", "i", file_index_type); declare_function("file_index_for_arch", "ii", "i", file_index_subtype); declare_function("entry_point_for_arch", "i", "i", ep_for_arch_type); declare_function("entry_point_for_arch", "ii", "i", ep_for_arch_subtype); end_declarations int module_initialize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_finalize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { YR_MEMORY_BLOCK* block; YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; foreach_memory_block(iterator, block) { const uint8_t* block_data = yr_fetch_block_data(block); if (block_data == NULL || block->size < 4) continue; // Parse Mach-O binary. if (is_macho_file_block((uint32_t*) block_data)) { macho_parse_file( block_data, block->size, block->base, module_object, context); break; } // Parse fat Mach-O binary. if (is_fat_macho_file_block((uint32_t*) block_data)) { macho_parse_fat_file( block_data, block->size, block->base, module_object, context); break; } } macho_set_definitions(module_object); return ERROR_SUCCESS; } int module_unload(YR_OBJECT* module_object) { return ERROR_SUCCESS; } yara-4.5.3/libyara/modules/magic/000077500000000000000000000000001501365277300166435ustar00rootroot00000000000000yara-4.5.3/libyara/modules/magic/magic.c000066400000000000000000000125111501365277300200670ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* The original idea and inspiration for this module comes from Armin Buescher. */ #include #include #include #define MODULE_NAME magic // Thread-local storage key used to store a pointer to a MAGIC_CACHE struct. YR_THREAD_STORAGE_KEY magic_tls; typedef struct { magic_t magic_cookie; const char* cached_type; const char* cached_mime_type; } MAGIC_CACHE; static int get_cache(MAGIC_CACHE** cache) { *cache = (MAGIC_CACHE*) yr_thread_storage_get_value(&magic_tls); if (*cache == NULL) { *cache = (MAGIC_CACHE*) yr_malloc(sizeof(MAGIC_CACHE)); if (*cache == NULL) return ERROR_INSUFFICIENT_MEMORY; (*cache)->magic_cookie = magic_open(0); if ((*cache)->magic_cookie == NULL) { yr_free(*cache); return ERROR_INSUFFICIENT_MEMORY; } if (magic_load((*cache)->magic_cookie, NULL) != 0) { magic_close((*cache)->magic_cookie); yr_free(*cache); return ERROR_INTERNAL_FATAL_ERROR; } (*cache)->cached_type = NULL; (*cache)->cached_mime_type = NULL; return yr_thread_storage_set_value(&magic_tls, *cache); } return ERROR_SUCCESS; } define_function(magic_mime_type) { YR_SCAN_CONTEXT* context = yr_scan_context(); YR_MEMORY_BLOCK* block; MAGIC_CACHE* cache; const uint8_t* block_data; if (context->flags & SCAN_FLAGS_PROCESS_MEMORY) return_string(YR_UNDEFINED); FAIL_ON_ERROR(get_cache(&cache)); if (cache->cached_mime_type == NULL) { block = first_memory_block(context); if (block == NULL) return_string(YR_UNDEFINED); block_data = yr_fetch_block_data(block); if (block_data != NULL) { magic_setflags(cache->magic_cookie, MAGIC_MIME_TYPE); const char* type = magic_buffer( cache->magic_cookie, block_data, block->size); cache->cached_mime_type = (type == NULL) ? NULL : yr_strdup(type); } } if (cache->cached_mime_type == NULL) return_string(YR_UNDEFINED); return_string((char*) cache->cached_mime_type); } define_function(magic_type) { MAGIC_CACHE* cache; YR_MEMORY_BLOCK* block; YR_SCAN_CONTEXT* context = yr_scan_context(); const uint8_t* block_data; if (context->flags & SCAN_FLAGS_PROCESS_MEMORY) return_string(YR_UNDEFINED); FAIL_ON_ERROR(get_cache(&cache)); if (cache->cached_type == NULL) { block = first_memory_block(context); if (block == NULL) return_string(YR_UNDEFINED); block_data = yr_fetch_block_data(block); if (block_data != NULL) { magic_setflags(cache->magic_cookie, 0); const char* type = magic_buffer( cache->magic_cookie, block_data, block->size); cache->cached_type = (type == NULL) ? NULL : yr_strdup(type); } } if (cache->cached_type == NULL) return_string(YR_UNDEFINED); return_string((char*) cache->cached_type); } begin_declarations declare_function("mime_type", "", "s", magic_mime_type); declare_function("type", "", "s", magic_type); end_declarations int module_initialize(YR_MODULE* module) { return yr_thread_storage_create(&magic_tls); } int module_finalize(YR_MODULE* module) { MAGIC_CACHE* cache = (MAGIC_CACHE*) yr_thread_storage_get_value(&magic_tls); if (cache != NULL) { magic_close(cache->magic_cookie); yr_free(cache); } return yr_thread_storage_destroy(&magic_tls); } int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { return ERROR_SUCCESS; } int module_unload(YR_OBJECT* module) { MAGIC_CACHE* cache = (MAGIC_CACHE*) yr_thread_storage_get_value(&magic_tls); if (cache != NULL) { if (cache->cached_type != NULL) yr_free((void*) cache->cached_type); if (cache->cached_mime_type != NULL) yr_free((void*) cache->cached_mime_type); cache->cached_type = NULL; cache->cached_mime_type = NULL; } return ERROR_SUCCESS; } yara-4.5.3/libyara/modules/math/000077500000000000000000000000001501365277300165145ustar00rootroot00000000000000yara-4.5.3/libyara/modules/math/math.c000066400000000000000000000455171501365277300176250ustar00rootroot00000000000000/* Copyright (c) 2014-2021. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #define MODULE_NAME math #define PI 3.141592653589793 // This is more than enough space to hold the maximum signed 64bit integer as a // string in decimal, hex or octal, including the sign and NULL terminator. #define INT64_MAX_STRING 30 // log2 is not defined by math.h in VC++ #if defined(_MSC_VER) && _MSC_VER < 1800 static double log2(double n) { return log(n) / log(2.0); } #endif uint32_t* get_distribution( int64_t offset, int64_t length, YR_SCAN_CONTEXT* context) { bool past_first_block = false; size_t i; uint32_t* data = (uint32_t*) yr_calloc(256, sizeof(uint32_t)); if (data == NULL) return NULL; YR_MEMORY_BLOCK* block = first_memory_block(context); YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; if (block == NULL || offset < 0 || length < 0 || offset < block->base) { yr_free(data); return NULL; } foreach_memory_block(iterator, block) { if (offset >= block->base && offset < block->base + block->size) { size_t data_offset = (size_t) (offset - block->base); size_t data_len = (size_t) yr_min( length, (size_t) (block->size - data_offset)); const uint8_t* block_data = yr_fetch_block_data(block); if (block_data == NULL) { yr_free(data); return NULL; } offset += data_len; length -= data_len; for (i = 0; i < data_len; i++) { uint8_t c = *(block_data + data_offset + i); data[c]++; } past_first_block = true; } else if (past_first_block) { // If offset is not within current block and we already // past the first block then the we are trying to compute // the distribution over a range of non contiguous blocks. As // range contains gaps of undefined data the distribution is // undefined. yr_free(data); return NULL; } if (block->base + block->size >= offset + length) break; } if (!past_first_block) { yr_free(data); return NULL; } return data; } uint32_t* get_distribution_global(YR_SCAN_CONTEXT* context) { size_t i; int64_t expected_next_offset = 0; uint32_t* data = (uint32_t*) yr_calloc(256, sizeof(uint32_t)); if (data == NULL) return NULL; YR_MEMORY_BLOCK* block; YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; foreach_memory_block(iterator, block) { if (expected_next_offset != block->base) { // If offset is not directly after the current block then // we are trying to compute the distribution over a range of non // contiguous blocks. As the range contains gaps of // undefined data the distribution is undefined. yr_free(data); return NULL; } const uint8_t* block_data = yr_fetch_block_data(block); if (block_data == NULL) { yr_free(data); return NULL; } for (i = 0; i < block->size; i++) { uint8_t c = *(block_data + i); data[c] += 1; } expected_next_offset = block->base + block->size; } return data; } define_function(string_entropy) { size_t i; double entropy = 0.0; SIZED_STRING* s = sized_string_argument(1); uint32_t* data = (uint32_t*) yr_calloc(256, sizeof(uint32_t)); if (data == NULL) return_float(YR_UNDEFINED); for (i = 0; i < s->length; i++) { uint8_t c = s->c_string[i]; data[c] += 1; } for (i = 0; i < 256; i++) { if (data[i] != 0) { double x = (double) (data[i]) / s->length; entropy -= x * log2(x); } } yr_free(data); return_float(entropy); } define_function(data_entropy) { double entropy = 0.0; int64_t offset = integer_argument(1); // offset where to start int64_t length = integer_argument(2); // length of bytes we want entropy on YR_SCAN_CONTEXT* context = yr_scan_context(); size_t i; size_t total_len = 0; uint32_t* data = get_distribution(offset, length, context); if (data == NULL) return_float(YR_UNDEFINED); for (i = 0; i < 256; i++) { total_len += data[i]; } for (i = 0; i < 256; i++) { if (data[i] != 0) { double x = (double) (data[i]) / total_len; entropy -= x * log2(x); } } yr_free(data); return_float(entropy); } define_function(string_deviation) { SIZED_STRING* s = sized_string_argument(1); double mean = float_argument(2); double sum = 0.0; size_t i; for (i = 0; i < s->length; i++) sum += fabs(((double) s->c_string[i]) - mean); return_float(sum / s->length); } define_function(data_deviation) { int64_t offset = integer_argument(1); int64_t length = integer_argument(2); double mean = float_argument(3); double sum = 0.0; size_t total_len = 0; size_t i; YR_SCAN_CONTEXT* context = yr_scan_context(); uint32_t* data = get_distribution(offset, length, context); if (data == NULL) return_float(YR_UNDEFINED); for (i = 0; i < 256; i++) { total_len += data[i]; sum += fabs(((double) i) - mean) * data[i]; } yr_free(data); return_float(sum / total_len); } define_function(string_mean) { size_t i; double sum = 0.0; SIZED_STRING* s = sized_string_argument(1); for (i = 0; i < s->length; i++) sum += (double) s->c_string[i]; return_float(sum / s->length); } define_function(data_mean) { double sum = 0.0; int64_t offset = integer_argument(1); int64_t length = integer_argument(2); YR_SCAN_CONTEXT* context = yr_scan_context(); size_t total_len = 0; size_t i; uint32_t* data = get_distribution(offset, length, context); if (data == NULL) return_float(YR_UNDEFINED); for (i = 0; i < 256; i++) { total_len += data[i]; sum += ((double) i) * data[i]; } yr_free(data); return_float(sum / total_len); } define_function(data_serial_correlation) { int past_first_block = false; size_t total_len = 0; size_t i; int64_t offset = integer_argument(1); int64_t length = integer_argument(2); YR_SCAN_CONTEXT* context = yr_scan_context(); YR_MEMORY_BLOCK* block = first_memory_block(context); YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; if (block == NULL) return_float(YR_UNDEFINED); double sccun = 0; double sccfirst = 0; double scclast = 0; double scct1 = 0; double scct2 = 0; double scct3 = 0; double scc = 0; if (offset < 0 || length < 0 || offset < block->base) return_float(YR_UNDEFINED); foreach_memory_block(iterator, block) { if (offset >= block->base && offset < block->base + block->size) { size_t data_offset = (size_t) (offset - block->base); size_t data_len = (size_t) yr_min( length, (size_t) (block->size - data_offset)); const uint8_t* block_data = yr_fetch_block_data(block); if (block_data == NULL) return_float(YR_UNDEFINED); total_len += data_len; offset += data_len; length -= data_len; for (i = 0; i < data_len; i++) { sccun = (double) *(block_data + data_offset + i); if (i == 0) { sccfirst = sccun; } scct1 += scclast * sccun; scct2 += sccun; scct3 += sccun * sccun; scclast = sccun; } past_first_block = true; } else if (past_first_block) { // If offset is not within current block and we already // past the first block then the we are trying to compute // the checksum over a range of non contiguous blocks. As // range contains gaps of undefined data the checksum is // undefined. return_float(YR_UNDEFINED); } if (block->base + block->size >= offset + length) break; } if (!past_first_block) return_float(YR_UNDEFINED); scct1 += scclast * sccfirst; scct2 *= scct2; scc = total_len * scct3 - scct2; if (scc == 0) scc = -100000; else scc = (total_len * scct1 - scct2) / scc; return_float(scc); } define_function(string_serial_correlation) { SIZED_STRING* s = sized_string_argument(1); double sccun = 0; double scclast = 0; double scct1 = 0; double scct2 = 0; double scct3 = 0; double scc = 0; size_t i; for (i = 0; i < s->length; i++) { sccun = (double) s->c_string[i]; scct1 += scclast * sccun; scct2 += sccun; scct3 += sccun * sccun; scclast = sccun; } if (s->length > 0) { scct1 += scclast * (double) s->c_string[0]; } scct2 *= scct2; scc = s->length * scct3 - scct2; if (scc == 0) scc = -100000; else scc = (s->length * scct1 - scct2) / scc; return_float(scc); } define_function(data_monte_carlo_pi) { int past_first_block = false; int mcount = 0; int inmont = 0; double INCIRC = pow(pow(256.0, 3.0) - 1, 2.0); double mpi = 0; size_t i; int64_t offset = integer_argument(1); int64_t length = integer_argument(2); YR_SCAN_CONTEXT* context = yr_scan_context(); YR_MEMORY_BLOCK* block = first_memory_block(context); YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; if (block == NULL) return_float(YR_UNDEFINED); if (offset < 0 || length < 0 || offset < block->base) return_float(YR_UNDEFINED); foreach_memory_block(iterator, block) { if (offset >= block->base && offset < block->base + block->size) { unsigned int monte[6]; size_t data_offset = (size_t) (offset - block->base); size_t data_len = (size_t) yr_min( length, (size_t) (block->size - data_offset)); const uint8_t* block_data = yr_fetch_block_data(block); if (block_data == NULL) return_float(YR_UNDEFINED); offset += data_len; length -= data_len; for (i = 0; i < data_len; i++) { monte[i % 6] = (unsigned int) *(block_data + data_offset + i); if (i % 6 == 5) { double mx = 0; double my = 0; int j; mcount++; for (j = 0; j < 3; j++) { mx = (mx * 256.0) + monte[j]; my = (my * 256.0) + monte[j + 3]; } if ((mx * mx + my * my) <= INCIRC) inmont++; } } past_first_block = true; } else if (past_first_block) { // If offset is not within current block and we already // past the first block then the we are trying to compute // the checksum over a range of non contiguous blocks. As // range contains gaps of undefined data the checksum is // undefined. return_float(YR_UNDEFINED); } if (block->base + block->size >= offset + length) break; } if (!past_first_block || mcount == 0) return_float(YR_UNDEFINED); mpi = 4.0 * ((double) inmont / mcount); return_float(fabs((mpi - PI) / PI)); } define_function(string_monte_carlo_pi) { SIZED_STRING* s = sized_string_argument(1); double INCIRC = pow(pow(256.0, 3.0) - 1, 2.0); double mpi = 0; unsigned int monte[6]; int mcount = 0; int inmont = 0; size_t i; for (i = 0; i < s->length; i++) { monte[i % 6] = (unsigned int) s->c_string[i]; if (i % 6 == 5) { double mx = 0; double my = 0; int j; mcount++; for (j = 0; j < 3; j++) { mx = (mx * 256.0) + monte[j]; my = (my * 256.0) + monte[j + 3]; } if ((mx * mx + my * my) <= INCIRC) inmont++; } } if (mcount == 0) return_float(YR_UNDEFINED); mpi = 4.0 * ((double) inmont / mcount); return_float(fabs((mpi - PI) / PI)); } define_function(in_range) { double test = float_argument(1); double lower = float_argument(2); double upper = float_argument(3); return_integer((lower <= test && test <= upper) ? 1 : 0); } // Undefine existing "min" and "max" macros in order to avoid conflicts with // function names. #undef min #undef max define_function(min) { uint64_t i = integer_argument(1); uint64_t j = integer_argument(2); return_integer(i < j ? i : j); } define_function(max) { uint64_t i = integer_argument(1); uint64_t j = integer_argument(2); return_integer(i > j ? i : j); } define_function(to_number) { return_integer(integer_argument(1) ? 1 : 0); } define_function(yr_math_abs) { return_integer(llabs(integer_argument(1))); } define_function(count_range) { int64_t byte = integer_argument(1); int64_t offset = integer_argument(2); int64_t length = integer_argument(3); if (byte < 0 || byte > 255) return_integer(YR_UNDEFINED); YR_SCAN_CONTEXT* context = yr_scan_context(); uint32_t* distribution = get_distribution(offset, length, context); if (distribution == NULL) return_integer(YR_UNDEFINED); int64_t count = (int64_t) distribution[byte]; yr_free(distribution); return_integer(count); } define_function(count_global) { int64_t byte = integer_argument(1); if (byte < 0 || byte > 255) return_integer(YR_UNDEFINED); YR_SCAN_CONTEXT* context = yr_scan_context(); uint32_t* distribution = get_distribution_global(context); if (distribution == NULL) return_integer(YR_UNDEFINED); int64_t count = (int64_t) distribution[byte]; yr_free(distribution); return_integer(count); } define_function(percentage_range) { int64_t byte = integer_argument(1); int64_t offset = integer_argument(2); int64_t length = integer_argument(3); if (byte < 0 || byte > 255) return_float(YR_UNDEFINED); YR_SCAN_CONTEXT* context = yr_scan_context(); uint32_t* distribution = get_distribution(offset, length, context); if (distribution == NULL) return_float(YR_UNDEFINED); int64_t count = (int64_t) distribution[byte]; int64_t total_count = 0; int64_t i; for (i = 0; i < 256; i++) total_count += distribution[i]; yr_free(distribution); return_float(((float) count) / ((float) total_count)); } define_function(percentage_global) { int64_t byte = integer_argument(1); if (byte < 0 || byte > 255) return_float(YR_UNDEFINED); YR_SCAN_CONTEXT* context = yr_scan_context(); uint32_t* distribution = get_distribution_global(context); if (distribution == NULL) return_float(YR_UNDEFINED); int64_t count = (int64_t) distribution[byte]; int64_t total_count = 0; int64_t i; for (i = 0; i < 256; i++) total_count += distribution[i]; yr_free(distribution); return_float(((float) count) / ((float) total_count)); } define_function(mode_range) { int64_t offset = integer_argument(1); int64_t length = integer_argument(2); YR_SCAN_CONTEXT* context = yr_scan_context(); uint32_t* distribution = get_distribution(offset, length, context); if (distribution == NULL) return_integer(YR_UNDEFINED); int64_t most_common = 0; size_t i; for (i = 0; i < 256; i++) { if (distribution[i] > distribution[most_common]) most_common = (int64_t) i; } yr_free(distribution); return_integer(most_common); } define_function(mode_global) { YR_SCAN_CONTEXT* context = yr_scan_context(); uint32_t* distribution = get_distribution_global(context); if (distribution == NULL) return_integer(YR_UNDEFINED); int64_t most_common = 0; size_t i; for (i = 0; i < 256; i++) { if (distribution[i] > distribution[most_common]) most_common = (int64_t) i; } yr_free(distribution); return_integer(most_common); } define_function(to_string) { int64_t i = integer_argument(1); char str[INT64_MAX_STRING]; snprintf(str, INT64_MAX_STRING, "%" PRId64, i); return_string(&str); } define_function(to_string_base) { int64_t i = integer_argument(1); int64_t base = integer_argument(2); char str[INT64_MAX_STRING]; char* fmt; switch (base) { case 10: fmt = "%" PRId64; break; case 8: fmt = "%" PRIo64; break; case 16: fmt = "%" PRIx64; break; default: return_string(YR_UNDEFINED); } snprintf(str, INT64_MAX_STRING, fmt, i); return_string(&str); } begin_declarations declare_float("MEAN_BYTES"); declare_function("in_range", "fff", "i", in_range); declare_function("deviation", "iif", "f", data_deviation); declare_function("deviation", "sf", "f", string_deviation); declare_function("mean", "ii", "f", data_mean); declare_function("mean", "s", "f", string_mean); declare_function("serial_correlation", "ii", "f", data_serial_correlation); declare_function("serial_correlation", "s", "f", string_serial_correlation); declare_function("monte_carlo_pi", "ii", "f", data_monte_carlo_pi); declare_function("monte_carlo_pi", "s", "f", string_monte_carlo_pi); declare_function("entropy", "ii", "f", data_entropy); declare_function("entropy", "s", "f", string_entropy); declare_function("min", "ii", "i", min); declare_function("max", "ii", "i", max); declare_function("to_number", "b", "i", to_number); declare_function("abs", "i", "i", yr_math_abs); declare_function("count", "iii", "i", count_range); declare_function("count", "i", "i", count_global); declare_function("percentage", "iii", "f", percentage_range); declare_function("percentage", "i", "f", percentage_global); declare_function("mode", "ii", "i", mode_range); declare_function("mode", "", "i", mode_global); declare_function("to_string", "i", "s", to_string); declare_function("to_string", "ii", "s", to_string_base); end_declarations int module_initialize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_finalize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { yr_set_float(127.5, module_object, "MEAN_BYTES"); return ERROR_SUCCESS; } int module_unload(YR_OBJECT* module_object) { return ERROR_SUCCESS; } yara-4.5.3/libyara/modules/module_list000066400000000000000000000006101501365277300200230ustar00rootroot00000000000000MODULE(tests) MODULE(pe) MODULE(elf) MODULE(math) MODULE(time) MODULE(console) MODULE(string) #ifdef DOTNET_MODULE MODULE(dotnet) #endif #ifdef CUCKOO_MODULE MODULE(cuckoo) #endif #ifdef MAGIC_MODULE MODULE(magic) #endif #ifdef HASH_MODULE MODULE(hash) #endif #ifdef MACHO_MODULE MODULE(macho) #endif #ifdef DEX_MODULE MODULE(dex) #endif #ifdef PB_TESTS_MODULE MODULE(pb_tests) #endif yara-4.5.3/libyara/modules/pb_tests/000077500000000000000000000000001501365277300174065ustar00rootroot00000000000000yara-4.5.3/libyara/modules/pb_tests/pb_tests.c000066400000000000000000000171561501365277300214070ustar00rootroot00000000000000 /* Generated by the protoc-gen-yara. DO NOT EDIT! */ #include #include #include "modules/pb_tests/pb_tests.pb-c.h" #define MODULE_NAME pb_tests static void* _pb_alloc(void* allocator_data, size_t size) { return yr_malloc(size); } static void _pb_free(void* allocator_data, void* pointer) { return yr_free(pointer); } begin_declarations begin_struct("struct") begin_struct("enum") declare_integer("FIRST"); declare_integer("SECOND"); end_struct("enum"); end_struct("struct"); declare_integer("f_int32"); declare_integer("f_int64"); declare_integer("f_sint32"); declare_integer("f_sint64"); declare_integer("f_sfixed32"); declare_integer("f_sfixed64"); declare_integer("f_bool"); declare_string("f_string"); declare_string("f_bytes"); begin_struct_array("f_struct_array") declare_string("f_string"); declare_integer("f_enum"); begin_struct("f_nested_struct") declare_integer("f_int32"); declare_string("f_string"); end_struct("f_nested_struct") begin_struct_array("f_nested_struct_array") declare_integer("f_int32"); declare_string("f_string"); end_struct_array("f_nested_struct_array"); end_struct_array("f_struct_array") declare_integer_dictionary("f_map_int32"); declare_integer_dictionary("f_map_bool"); declare_string_dictionary("f_map_string"); declare_float_dictionary("f_map_float"); begin_struct_dictionary("f_map_struct") declare_integer("f_int32"); declare_integer("f_int64"); end_struct_dictionary("f_map_struct") declare_string("f_oneof_string"); begin_struct("f_oneof_struct") declare_integer("f_int32"); declare_integer("f_int64"); end_struct("f_oneof_struct") declare_string("f_yara_name"); end_declarations int module_initialize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_finalize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_unload(YR_OBJECT* module_object) { return ERROR_SUCCESS; } int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { ProtobufCAllocator allocator; allocator.alloc = _pb_alloc; allocator.free = _pb_free; if (module_data == NULL) return ERROR_SUCCESS; Test__RootMessage* pb = test__root_message__unpack( &allocator, module_data_size, module_data); if (pb == NULL) return ERROR_INVALID_MODULE_DATA; yr_set_integer(0, module_object, "struct.enum.FIRST"); yr_set_integer(1, module_object, "struct.enum.SECOND"); if (pb->has_f_int32) { yr_set_integer(pb->f_int32, module_object, "f_int32"); } if (pb->has_f_int64) { yr_set_integer(pb->f_int64, module_object, "f_int64"); } if (pb->has_f_sint32) { yr_set_integer(pb->f_sint32, module_object, "f_sint32"); } if (pb->has_f_sint64) { yr_set_integer(pb->f_sint64, module_object, "f_sint64"); } if (pb->has_f_sfixed32) { yr_set_integer(pb->f_sfixed32, module_object, "f_sfixed32"); } if (pb->has_f_sfixed64) { yr_set_integer(pb->f_sfixed64, module_object, "f_sfixed64"); } if (pb->has_f_bool) { yr_set_integer(pb->f_bool, module_object, "f_bool"); } yr_set_string(pb->f_string, module_object, "f_string"); yr_set_sized_string( (const char*) pb->f_bytes.data, pb->f_bytes.len, module_object, "f_bytes"); for (int i = 0; i < pb->n_f_struct_array; i++) { if (pb->f_struct_array[i] != NULL) { yr_set_string( pb->f_struct_array[i]->f_string, module_object, "f_struct_array[%i].f_string", i); if (pb->f_struct_array[i]->has_f_enum) { yr_set_integer( pb->f_struct_array[i]->f_enum, module_object, "f_struct_array[%i].f_enum", i); } if (pb->f_struct_array[i]->f_nested_struct != NULL) { if (pb->f_struct_array[i]->f_nested_struct->has_f_int32) { yr_set_integer( pb->f_struct_array[i]->f_nested_struct->f_int32, module_object, "f_struct_array[%i].f_nested_struct.f_int32", i); } yr_set_string( pb->f_struct_array[i]->f_nested_struct->f_string, module_object, "f_struct_array[%i].f_nested_struct.f_string", i); } for (int j = 0; j < pb->f_struct_array[i]->n_f_nested_struct_array; j++) { if (pb->f_struct_array[i]->f_nested_struct_array[j] != NULL) { if (pb->f_struct_array[i]->f_nested_struct_array[j]->has_f_int32) { yr_set_integer( pb->f_struct_array[i]->f_nested_struct_array[j]->f_int32, module_object, "f_struct_array[%i].f_nested_struct_array[%i].f_int32", i, j); } yr_set_string( pb->f_struct_array[i]->f_nested_struct_array[j]->f_string, module_object, "f_struct_array[%i].f_nested_struct_array[%i].f_string", i, j); } } } } for (int i = 0; i < pb->n_f_map_int32; i++) { if (pb->f_map_int32[i] != NULL) { if (pb->f_map_int32[i]->has_value) { yr_set_integer( pb->f_map_int32[i]->value, module_object, "f_map_int32[%s]", pb->f_map_int32[i]->key); } } } for (int i = 0; i < pb->n_f_map_bool; i++) { if (pb->f_map_bool[i] != NULL) { if (pb->f_map_bool[i]->has_value) { yr_set_integer( pb->f_map_bool[i]->value, module_object, "f_map_bool[%s]", pb->f_map_bool[i]->key); } } } for (int i = 0; i < pb->n_f_map_string; i++) { if (pb->f_map_string[i] != NULL) { yr_set_string( pb->f_map_string[i]->value, module_object, "f_map_string[%s]", pb->f_map_string[i]->key); } } for (int i = 0; i < pb->n_f_map_float; i++) { if (pb->f_map_float[i] != NULL) { if (pb->f_map_float[i]->has_value) { yr_set_float( pb->f_map_float[i]->value, module_object, "f_map_float[%s]", pb->f_map_float[i]->key); } } } for (int i = 0; i < pb->n_f_map_struct; i++) { if (pb->f_map_struct[i] != NULL) { if (pb->f_map_struct[i]->value != NULL) { if (pb->f_map_struct[i]->value->has_f_int32) { yr_set_integer( pb->f_map_struct[i]->value->f_int32, module_object, "f_map_struct[%s].f_int32", pb->f_map_struct[i]->key); } if (pb->f_map_struct[i]->value->has_f_int64) { yr_set_integer( pb->f_map_struct[i]->value->f_int64, module_object, "f_map_struct[%s].f_int64", pb->f_map_struct[i]->key); } } } } if (pb->f_oneof_case == 20) { yr_set_string(pb->f_oneof_string, module_object, "f_oneof_string"); } if (pb->f_oneof_case == 21) { if (pb->f_oneof_struct != NULL) { if (pb->f_oneof_struct->has_f_int32) { yr_set_integer( pb->f_oneof_struct->f_int32, module_object, "f_oneof_struct.f_int32"); } if (pb->f_oneof_struct->has_f_int64) { yr_set_integer( pb->f_oneof_struct->f_int64, module_object, "f_oneof_struct.f_int64"); } } } yr_set_string(pb->f_renamed, module_object, "f_yara_name"); test__root_message__free_unpacked(pb, &allocator); return ERROR_SUCCESS; } yara-4.5.3/libyara/modules/pb_tests/pb_tests.pb-c.c000066400000000000000000000732341501365277300222260ustar00rootroot00000000000000/* Generated by the protocol buffer compiler. DO NOT EDIT! */ /* Generated from: modules/pb_tests/pb_tests.proto */ /* Do not generate deprecated warnings for self */ #ifndef PROTOBUF_C__NO_DEPRECATED #define PROTOBUF_C__NO_DEPRECATED #endif #include "modules/pb_tests/pb_tests.pb-c.h" void test__struct__nested_struct__init(Test__Struct__NestedStruct *message) { static const Test__Struct__NestedStruct init_value = TEST__STRUCT__NESTED_STRUCT__INIT; *message = init_value; } void test__struct__init(Test__Struct *message) { static const Test__Struct init_value = TEST__STRUCT__INIT; *message = init_value; } size_t test__struct__get_packed_size(const Test__Struct *message) { assert(message->base.descriptor == &test__struct__descriptor); return protobuf_c_message_get_packed_size( (const ProtobufCMessage *) (message)); } size_t test__struct__pack(const Test__Struct *message, uint8_t *out) { assert(message->base.descriptor == &test__struct__descriptor); return protobuf_c_message_pack((const ProtobufCMessage *) message, out); } size_t test__struct__pack_to_buffer( const Test__Struct *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &test__struct__descriptor); return protobuf_c_message_pack_to_buffer( (const ProtobufCMessage *) message, buffer); } Test__Struct *test__struct__unpack( ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (Test__Struct *) protobuf_c_message_unpack( &test__struct__descriptor, allocator, len, data); } void test__struct__free_unpacked( Test__Struct *message, ProtobufCAllocator *allocator) { if (!message) return; assert(message->base.descriptor == &test__struct__descriptor); protobuf_c_message_free_unpacked((ProtobufCMessage *) message, allocator); } void test__map_struct__init(Test__MapStruct *message) { static const Test__MapStruct init_value = TEST__MAP_STRUCT__INIT; *message = init_value; } size_t test__map_struct__get_packed_size(const Test__MapStruct *message) { assert(message->base.descriptor == &test__map_struct__descriptor); return protobuf_c_message_get_packed_size( (const ProtobufCMessage *) (message)); } size_t test__map_struct__pack(const Test__MapStruct *message, uint8_t *out) { assert(message->base.descriptor == &test__map_struct__descriptor); return protobuf_c_message_pack((const ProtobufCMessage *) message, out); } size_t test__map_struct__pack_to_buffer( const Test__MapStruct *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &test__map_struct__descriptor); return protobuf_c_message_pack_to_buffer( (const ProtobufCMessage *) message, buffer); } Test__MapStruct *test__map_struct__unpack( ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (Test__MapStruct *) protobuf_c_message_unpack( &test__map_struct__descriptor, allocator, len, data); } void test__map_struct__free_unpacked( Test__MapStruct *message, ProtobufCAllocator *allocator) { if (!message) return; assert(message->base.descriptor == &test__map_struct__descriptor); protobuf_c_message_free_unpacked((ProtobufCMessage *) message, allocator); } void test__root_message__fmap_int32_entry__init( Test__RootMessage__FMapInt32Entry *message) { static const Test__RootMessage__FMapInt32Entry init_value = TEST__ROOT_MESSAGE__FMAP_INT32_ENTRY__INIT; *message = init_value; } void test__root_message__fmap_bool_entry__init( Test__RootMessage__FMapBoolEntry *message) { static const Test__RootMessage__FMapBoolEntry init_value = TEST__ROOT_MESSAGE__FMAP_BOOL_ENTRY__INIT; *message = init_value; } void test__root_message__fmap_string_entry__init( Test__RootMessage__FMapStringEntry *message) { static const Test__RootMessage__FMapStringEntry init_value = TEST__ROOT_MESSAGE__FMAP_STRING_ENTRY__INIT; *message = init_value; } void test__root_message__fmap_float_entry__init( Test__RootMessage__FMapFloatEntry *message) { static const Test__RootMessage__FMapFloatEntry init_value = TEST__ROOT_MESSAGE__FMAP_FLOAT_ENTRY__INIT; *message = init_value; } void test__root_message__fmap_struct_entry__init( Test__RootMessage__FMapStructEntry *message) { static const Test__RootMessage__FMapStructEntry init_value = TEST__ROOT_MESSAGE__FMAP_STRUCT_ENTRY__INIT; *message = init_value; } void test__root_message__init(Test__RootMessage *message) { static const Test__RootMessage init_value = TEST__ROOT_MESSAGE__INIT; *message = init_value; } size_t test__root_message__get_packed_size(const Test__RootMessage *message) { assert(message->base.descriptor == &test__root_message__descriptor); return protobuf_c_message_get_packed_size( (const ProtobufCMessage *) (message)); } size_t test__root_message__pack(const Test__RootMessage *message, uint8_t *out) { assert(message->base.descriptor == &test__root_message__descriptor); return protobuf_c_message_pack((const ProtobufCMessage *) message, out); } size_t test__root_message__pack_to_buffer( const Test__RootMessage *message, ProtobufCBuffer *buffer) { assert(message->base.descriptor == &test__root_message__descriptor); return protobuf_c_message_pack_to_buffer( (const ProtobufCMessage *) message, buffer); } Test__RootMessage *test__root_message__unpack( ProtobufCAllocator *allocator, size_t len, const uint8_t *data) { return (Test__RootMessage *) protobuf_c_message_unpack( &test__root_message__descriptor, allocator, len, data); } void test__root_message__free_unpacked( Test__RootMessage *message, ProtobufCAllocator *allocator) { if (!message) return; assert(message->base.descriptor == &test__root_message__descriptor); protobuf_c_message_free_unpacked((ProtobufCMessage *) message, allocator); } static const ProtobufCFieldDescriptor test__struct__nested_struct__field_descriptors[2] = { { "f_int32", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_INT32, offsetof(Test__Struct__NestedStruct, has_f_int32), offsetof(Test__Struct__NestedStruct, f_int32), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_string", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_STRING, 0, /* quantifier_offset */ offsetof(Test__Struct__NestedStruct, f_string), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, }; static const unsigned test__struct__nested_struct__field_indices_by_name[] = { 0, /* field[0] = f_int32 */ 1, /* field[1] = f_string */ }; static const ProtobufCIntRange test__struct__nested_struct__number_ranges[1 + 1] = {{1, 0}, {0, 2}}; const ProtobufCMessageDescriptor test__struct__nested_struct__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "test.Struct.NestedStruct", "NestedStruct", "Test__Struct__NestedStruct", "test", sizeof(Test__Struct__NestedStruct), 2, test__struct__nested_struct__field_descriptors, test__struct__nested_struct__field_indices_by_name, 1, test__struct__nested_struct__number_ranges, (ProtobufCMessageInit) test__struct__nested_struct__init, NULL, NULL, NULL /* reserved[123] */ }; static const ProtobufCEnumValue test__struct__enum__enum_values_by_number[2] = { {"FIRST", "TEST__STRUCT__ENUM__FIRST", 0}, {"SECOND", "TEST__STRUCT__ENUM__SECOND", 1}, }; static const ProtobufCIntRange test__struct__enum__value_ranges[] = { {0, 0}, {0, 2}}; static const ProtobufCEnumValueIndex test__struct__enum__enum_values_by_name[2] = { {"FIRST", 0}, {"SECOND", 1}, }; const ProtobufCEnumDescriptor test__struct__enum__descriptor = { PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC, "test.Struct.Enum", "Enum", "Test__Struct__Enum", "test", 2, test__struct__enum__enum_values_by_number, 2, test__struct__enum__enum_values_by_name, 1, test__struct__enum__value_ranges, NULL, NULL, NULL, NULL /* reserved[1234] */ }; static const ProtobufCFieldDescriptor test__struct__field_descriptors[4] = { { "f_string", 1, PROTOBUF_C_LABEL_REQUIRED, PROTOBUF_C_TYPE_STRING, 0, /* quantifier_offset */ offsetof(Test__Struct, f_string), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_enum", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_ENUM, offsetof(Test__Struct, has_f_enum), offsetof(Test__Struct, f_enum), &test__struct__enum__descriptor, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_nested_struct", 3, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(Test__Struct, f_nested_struct), &test__struct__nested_struct__descriptor, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_nested_struct_array", 4, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(Test__Struct, n_f_nested_struct_array), offsetof(Test__Struct, f_nested_struct_array), &test__struct__nested_struct__descriptor, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, }; static const unsigned test__struct__field_indices_by_name[] = { 1, /* field[1] = f_enum */ 2, /* field[2] = f_nested_struct */ 3, /* field[3] = f_nested_struct_array */ 0, /* field[0] = f_string */ }; static const ProtobufCIntRange test__struct__number_ranges[1 + 1] = { {1, 0}, {0, 4}}; const ProtobufCMessageDescriptor test__struct__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "test.Struct", "Struct", "Test__Struct", "test", sizeof(Test__Struct), 4, test__struct__field_descriptors, test__struct__field_indices_by_name, 1, test__struct__number_ranges, (ProtobufCMessageInit) test__struct__init, NULL, NULL, NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor test__map_struct__field_descriptors[2] = { { "f_int32", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_INT32, offsetof(Test__MapStruct, has_f_int32), offsetof(Test__MapStruct, f_int32), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_int64", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_INT64, offsetof(Test__MapStruct, has_f_int64), offsetof(Test__MapStruct, f_int64), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, }; static const unsigned test__map_struct__field_indices_by_name[] = { 0, /* field[0] = f_int32 */ 1, /* field[1] = f_int64 */ }; static const ProtobufCIntRange test__map_struct__number_ranges[1 + 1] = { {1, 0}, {0, 2}}; const ProtobufCMessageDescriptor test__map_struct__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "test.MapStruct", "MapStruct", "Test__MapStruct", "test", sizeof(Test__MapStruct), 2, test__map_struct__field_descriptors, test__map_struct__field_indices_by_name, 1, test__map_struct__number_ranges, (ProtobufCMessageInit) test__map_struct__init, NULL, NULL, NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor test__root_message__fmap_int32_entry__field_descriptors[2] = { { "key", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_STRING, 0, /* quantifier_offset */ offsetof(Test__RootMessage__FMapInt32Entry, key), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "value", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_INT32, offsetof(Test__RootMessage__FMapInt32Entry, has_value), offsetof(Test__RootMessage__FMapInt32Entry, value), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, }; static const unsigned test__root_message__fmap_int32_entry__field_indices_by_name[] = { 0, /* field[0] = key */ 1, /* field[1] = value */ }; static const ProtobufCIntRange test__root_message__fmap_int32_entry__number_ranges[1 + 1] = { {1, 0}, {0, 2}}; const ProtobufCMessageDescriptor test__root_message__fmap_int32_entry__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "test.RootMessage.FMapInt32Entry", "FMapInt32Entry", "Test__RootMessage__FMapInt32Entry", "test", sizeof(Test__RootMessage__FMapInt32Entry), 2, test__root_message__fmap_int32_entry__field_descriptors, test__root_message__fmap_int32_entry__field_indices_by_name, 1, test__root_message__fmap_int32_entry__number_ranges, (ProtobufCMessageInit) test__root_message__fmap_int32_entry__init, NULL, NULL, NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor test__root_message__fmap_bool_entry__field_descriptors[2] = { { "key", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_STRING, 0, /* quantifier_offset */ offsetof(Test__RootMessage__FMapBoolEntry, key), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "value", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BOOL, offsetof(Test__RootMessage__FMapBoolEntry, has_value), offsetof(Test__RootMessage__FMapBoolEntry, value), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, }; static const unsigned test__root_message__fmap_bool_entry__field_indices_by_name[] = { 0, /* field[0] = key */ 1, /* field[1] = value */ }; static const ProtobufCIntRange test__root_message__fmap_bool_entry__number_ranges[1 + 1] = { {1, 0}, {0, 2}}; const ProtobufCMessageDescriptor test__root_message__fmap_bool_entry__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "test.RootMessage.FMapBoolEntry", "FMapBoolEntry", "Test__RootMessage__FMapBoolEntry", "test", sizeof(Test__RootMessage__FMapBoolEntry), 2, test__root_message__fmap_bool_entry__field_descriptors, test__root_message__fmap_bool_entry__field_indices_by_name, 1, test__root_message__fmap_bool_entry__number_ranges, (ProtobufCMessageInit) test__root_message__fmap_bool_entry__init, NULL, NULL, NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor test__root_message__fmap_string_entry__field_descriptors[2] = { { "key", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_STRING, 0, /* quantifier_offset */ offsetof(Test__RootMessage__FMapStringEntry, key), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "value", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_STRING, 0, /* quantifier_offset */ offsetof(Test__RootMessage__FMapStringEntry, value), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, }; static const unsigned test__root_message__fmap_string_entry__field_indices_by_name[] = { 0, /* field[0] = key */ 1, /* field[1] = value */ }; static const ProtobufCIntRange test__root_message__fmap_string_entry__number_ranges[1 + 1] = { {1, 0}, {0, 2}}; const ProtobufCMessageDescriptor test__root_message__fmap_string_entry__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "test.RootMessage.FMapStringEntry", "FMapStringEntry", "Test__RootMessage__FMapStringEntry", "test", sizeof(Test__RootMessage__FMapStringEntry), 2, test__root_message__fmap_string_entry__field_descriptors, test__root_message__fmap_string_entry__field_indices_by_name, 1, test__root_message__fmap_string_entry__number_ranges, (ProtobufCMessageInit) test__root_message__fmap_string_entry__init, NULL, NULL, NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor test__root_message__fmap_float_entry__field_descriptors[2] = { { "key", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_STRING, 0, /* quantifier_offset */ offsetof(Test__RootMessage__FMapFloatEntry, key), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "value", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_FLOAT, offsetof(Test__RootMessage__FMapFloatEntry, has_value), offsetof(Test__RootMessage__FMapFloatEntry, value), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, }; static const unsigned test__root_message__fmap_float_entry__field_indices_by_name[] = { 0, /* field[0] = key */ 1, /* field[1] = value */ }; static const ProtobufCIntRange test__root_message__fmap_float_entry__number_ranges[1 + 1] = { {1, 0}, {0, 2}}; const ProtobufCMessageDescriptor test__root_message__fmap_float_entry__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "test.RootMessage.FMapFloatEntry", "FMapFloatEntry", "Test__RootMessage__FMapFloatEntry", "test", sizeof(Test__RootMessage__FMapFloatEntry), 2, test__root_message__fmap_float_entry__field_descriptors, test__root_message__fmap_float_entry__field_indices_by_name, 1, test__root_message__fmap_float_entry__number_ranges, (ProtobufCMessageInit) test__root_message__fmap_float_entry__init, NULL, NULL, NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor test__root_message__fmap_struct_entry__field_descriptors[2] = { { "key", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_STRING, 0, /* quantifier_offset */ offsetof(Test__RootMessage__FMapStructEntry, key), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "value", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, 0, /* quantifier_offset */ offsetof(Test__RootMessage__FMapStructEntry, value), &test__map_struct__descriptor, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, }; static const unsigned test__root_message__fmap_struct_entry__field_indices_by_name[] = { 0, /* field[0] = key */ 1, /* field[1] = value */ }; static const ProtobufCIntRange test__root_message__fmap_struct_entry__number_ranges[1 + 1] = { {1, 0}, {0, 2}}; const ProtobufCMessageDescriptor test__root_message__fmap_struct_entry__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "test.RootMessage.FMapStructEntry", "FMapStructEntry", "Test__RootMessage__FMapStructEntry", "test", sizeof(Test__RootMessage__FMapStructEntry), 2, test__root_message__fmap_struct_entry__field_descriptors, test__root_message__fmap_struct_entry__field_indices_by_name, 1, test__root_message__fmap_struct_entry__number_ranges, (ProtobufCMessageInit) test__root_message__fmap_struct_entry__init, NULL, NULL, NULL /* reserved[123] */ }; static const ProtobufCFieldDescriptor test__root_message__field_descriptors[19] = { { "f_int32", 1, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_INT32, offsetof(Test__RootMessage, has_f_int32), offsetof(Test__RootMessage, f_int32), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_int64", 2, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_INT64, offsetof(Test__RootMessage, has_f_int64), offsetof(Test__RootMessage, f_int64), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_sint32", 5, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_SINT32, offsetof(Test__RootMessage, has_f_sint32), offsetof(Test__RootMessage, f_sint32), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_sint64", 6, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_SINT64, offsetof(Test__RootMessage, has_f_sint64), offsetof(Test__RootMessage, f_sint64), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_sfixed32", 9, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_SFIXED32, offsetof(Test__RootMessage, has_f_sfixed32), offsetof(Test__RootMessage, f_sfixed32), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_sfixed64", 10, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_SFIXED64, offsetof(Test__RootMessage, has_f_sfixed64), offsetof(Test__RootMessage, f_sfixed64), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_bool", 11, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BOOL, offsetof(Test__RootMessage, has_f_bool), offsetof(Test__RootMessage, f_bool), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_string", 12, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_STRING, 0, /* quantifier_offset */ offsetof(Test__RootMessage, f_string), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_bytes", 13, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_BYTES, offsetof(Test__RootMessage, has_f_bytes), offsetof(Test__RootMessage, f_bytes), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_struct_array", 14, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(Test__RootMessage, n_f_struct_array), offsetof(Test__RootMessage, f_struct_array), &test__struct__descriptor, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_map_int32", 15, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(Test__RootMessage, n_f_map_int32), offsetof(Test__RootMessage, f_map_int32), &test__root_message__fmap_int32_entry__descriptor, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_map_bool", 16, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(Test__RootMessage, n_f_map_bool), offsetof(Test__RootMessage, f_map_bool), &test__root_message__fmap_bool_entry__descriptor, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_map_string", 17, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(Test__RootMessage, n_f_map_string), offsetof(Test__RootMessage, f_map_string), &test__root_message__fmap_string_entry__descriptor, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_map_float", 18, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(Test__RootMessage, n_f_map_float), offsetof(Test__RootMessage, f_map_float), &test__root_message__fmap_float_entry__descriptor, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_map_struct", 19, PROTOBUF_C_LABEL_REPEATED, PROTOBUF_C_TYPE_MESSAGE, offsetof(Test__RootMessage, n_f_map_struct), offsetof(Test__RootMessage, f_map_struct), &test__root_message__fmap_struct_entry__descriptor, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_oneof_string", 20, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_STRING, offsetof(Test__RootMessage, f_oneof_case), offsetof(Test__RootMessage, f_oneof_string), NULL, NULL, 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_oneof_struct", 21, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_MESSAGE, offsetof(Test__RootMessage, f_oneof_case), offsetof(Test__RootMessage, f_oneof_struct), &test__map_struct__descriptor, NULL, 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_ignored", 22, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_STRING, 0, /* quantifier_offset */ offsetof(Test__RootMessage, f_ignored), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, { "f_renamed", 23, PROTOBUF_C_LABEL_OPTIONAL, PROTOBUF_C_TYPE_STRING, 0, /* quantifier_offset */ offsetof(Test__RootMessage, f_renamed), NULL, NULL, 0, /* flags */ 0, NULL, NULL /* reserved1,reserved2, etc */ }, }; static const unsigned test__root_message__field_indices_by_name[] = { 6, /* field[6] = f_bool */ 8, /* field[8] = f_bytes */ 17, /* field[17] = f_ignored */ 0, /* field[0] = f_int32 */ 1, /* field[1] = f_int64 */ 11, /* field[11] = f_map_bool */ 13, /* field[13] = f_map_float */ 10, /* field[10] = f_map_int32 */ 12, /* field[12] = f_map_string */ 14, /* field[14] = f_map_struct */ 15, /* field[15] = f_oneof_string */ 16, /* field[16] = f_oneof_struct */ 18, /* field[18] = f_renamed */ 4, /* field[4] = f_sfixed32 */ 5, /* field[5] = f_sfixed64 */ 2, /* field[2] = f_sint32 */ 3, /* field[3] = f_sint64 */ 7, /* field[7] = f_string */ 9, /* field[9] = f_struct_array */ }; static const ProtobufCIntRange test__root_message__number_ranges[3 + 1] = { {1, 0}, {5, 2}, {9, 4}, {0, 19}}; const ProtobufCMessageDescriptor test__root_message__descriptor = { PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, "test.RootMessage", "RootMessage", "Test__RootMessage", "test", sizeof(Test__RootMessage), 19, test__root_message__field_descriptors, test__root_message__field_indices_by_name, 3, test__root_message__number_ranges, (ProtobufCMessageInit) test__root_message__init, NULL, NULL, NULL /* reserved[123] */ }; yara-4.5.3/libyara/modules/pb_tests/pb_tests.pb-c.h000066400000000000000000000270361501365277300222320ustar00rootroot00000000000000/* Generated by the protocol buffer compiler. DO NOT EDIT! */ /* Generated from: modules/pb_tests/pb_tests.proto */ #ifndef PROTOBUF_C_modules_2fpb_5ftests_2fpb_5ftests_2eproto__INCLUDED #define PROTOBUF_C_modules_2fpb_5ftests_2fpb_5ftests_2eproto__INCLUDED #include PROTOBUF_C__BEGIN_DECLS #if PROTOBUF_C_VERSION_NUMBER < 1000000 # error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. #elif 1003002 < PROTOBUF_C_MIN_COMPILER_VERSION # error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. #endif #include "yara.pb-c.h" typedef struct _Test__Struct Test__Struct; typedef struct _Test__Struct__NestedStruct Test__Struct__NestedStruct; typedef struct _Test__MapStruct Test__MapStruct; typedef struct _Test__RootMessage Test__RootMessage; typedef struct _Test__RootMessage__FMapInt32Entry Test__RootMessage__FMapInt32Entry; typedef struct _Test__RootMessage__FMapBoolEntry Test__RootMessage__FMapBoolEntry; typedef struct _Test__RootMessage__FMapStringEntry Test__RootMessage__FMapStringEntry; typedef struct _Test__RootMessage__FMapFloatEntry Test__RootMessage__FMapFloatEntry; typedef struct _Test__RootMessage__FMapStructEntry Test__RootMessage__FMapStructEntry; /* --- enums --- */ typedef enum _Test__Struct__Enum { TEST__STRUCT__ENUM__FIRST = 0, TEST__STRUCT__ENUM__SECOND = 1 PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(TEST__STRUCT__ENUM) } Test__Struct__Enum; /* --- messages --- */ struct _Test__Struct__NestedStruct { ProtobufCMessage base; protobuf_c_boolean has_f_int32; int32_t f_int32; char *f_string; }; #define TEST__STRUCT__NESTED_STRUCT__INIT \ { PROTOBUF_C_MESSAGE_INIT (&test__struct__nested_struct__descriptor) \ , 0, 0, NULL } struct _Test__Struct { ProtobufCMessage base; char *f_string; protobuf_c_boolean has_f_enum; Test__Struct__Enum f_enum; Test__Struct__NestedStruct *f_nested_struct; size_t n_f_nested_struct_array; Test__Struct__NestedStruct **f_nested_struct_array; }; #define TEST__STRUCT__INIT \ { PROTOBUF_C_MESSAGE_INIT (&test__struct__descriptor) \ , NULL, 0, TEST__STRUCT__ENUM__FIRST, NULL, 0,NULL } struct _Test__MapStruct { ProtobufCMessage base; protobuf_c_boolean has_f_int32; int32_t f_int32; protobuf_c_boolean has_f_int64; int64_t f_int64; }; #define TEST__MAP_STRUCT__INIT \ { PROTOBUF_C_MESSAGE_INIT (&test__map_struct__descriptor) \ , 0, 0, 0, 0 } struct _Test__RootMessage__FMapInt32Entry { ProtobufCMessage base; char *key; protobuf_c_boolean has_value; int32_t value; }; #define TEST__ROOT_MESSAGE__FMAP_INT32_ENTRY__INIT \ { PROTOBUF_C_MESSAGE_INIT (&test__root_message__fmap_int32_entry__descriptor) \ , NULL, 0, 0 } struct _Test__RootMessage__FMapBoolEntry { ProtobufCMessage base; char *key; protobuf_c_boolean has_value; protobuf_c_boolean value; }; #define TEST__ROOT_MESSAGE__FMAP_BOOL_ENTRY__INIT \ { PROTOBUF_C_MESSAGE_INIT (&test__root_message__fmap_bool_entry__descriptor) \ , NULL, 0, 0 } struct _Test__RootMessage__FMapStringEntry { ProtobufCMessage base; char *key; char *value; }; #define TEST__ROOT_MESSAGE__FMAP_STRING_ENTRY__INIT \ { PROTOBUF_C_MESSAGE_INIT (&test__root_message__fmap_string_entry__descriptor) \ , NULL, NULL } struct _Test__RootMessage__FMapFloatEntry { ProtobufCMessage base; char *key; protobuf_c_boolean has_value; float value; }; #define TEST__ROOT_MESSAGE__FMAP_FLOAT_ENTRY__INIT \ { PROTOBUF_C_MESSAGE_INIT (&test__root_message__fmap_float_entry__descriptor) \ , NULL, 0, 0 } struct _Test__RootMessage__FMapStructEntry { ProtobufCMessage base; char *key; Test__MapStruct *value; }; #define TEST__ROOT_MESSAGE__FMAP_STRUCT_ENTRY__INIT \ { PROTOBUF_C_MESSAGE_INIT (&test__root_message__fmap_struct_entry__descriptor) \ , NULL, NULL } typedef enum { TEST__ROOT_MESSAGE__F_ONEOF__NOT_SET = 0, TEST__ROOT_MESSAGE__F_ONEOF_F_ONEOF_STRING = 20, TEST__ROOT_MESSAGE__F_ONEOF_F_ONEOF_STRUCT = 21 PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(TEST__ROOT_MESSAGE__F_ONEOF) } Test__RootMessage__FOneofCase; struct _Test__RootMessage { ProtobufCMessage base; protobuf_c_boolean has_f_int32; int32_t f_int32; protobuf_c_boolean has_f_int64; int64_t f_int64; /* *optional uint32 f_uint32 = 3; // not supported *optional uint64 f_uint64 = 4; // not supported */ protobuf_c_boolean has_f_sint32; int32_t f_sint32; protobuf_c_boolean has_f_sint64; int64_t f_sint64; /* *optional fixed32 f_fixed32 = 7; // not supported *optional fixed64 f_fixed64 = 8; // not supported */ protobuf_c_boolean has_f_sfixed32; int32_t f_sfixed32; protobuf_c_boolean has_f_sfixed64; int64_t f_sfixed64; protobuf_c_boolean has_f_bool; protobuf_c_boolean f_bool; char *f_string; protobuf_c_boolean has_f_bytes; ProtobufCBinaryData f_bytes; size_t n_f_struct_array; Test__Struct **f_struct_array; size_t n_f_map_int32; Test__RootMessage__FMapInt32Entry **f_map_int32; size_t n_f_map_bool; Test__RootMessage__FMapBoolEntry **f_map_bool; size_t n_f_map_string; Test__RootMessage__FMapStringEntry **f_map_string; size_t n_f_map_float; Test__RootMessage__FMapFloatEntry **f_map_float; size_t n_f_map_struct; Test__RootMessage__FMapStructEntry **f_map_struct; char *f_ignored; char *f_renamed; Test__RootMessage__FOneofCase f_oneof_case; union { char *f_oneof_string; Test__MapStruct *f_oneof_struct; }; }; #define TEST__ROOT_MESSAGE__INIT \ { PROTOBUF_C_MESSAGE_INIT (&test__root_message__descriptor) \ , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0, {0,NULL}, 0,NULL, 0,NULL, 0,NULL, 0,NULL, 0,NULL, 0,NULL, NULL, NULL, TEST__ROOT_MESSAGE__F_ONEOF__NOT_SET, {0} } /* Test__Struct__NestedStruct methods */ void test__struct__nested_struct__init (Test__Struct__NestedStruct *message); /* Test__Struct methods */ void test__struct__init (Test__Struct *message); size_t test__struct__get_packed_size (const Test__Struct *message); size_t test__struct__pack (const Test__Struct *message, uint8_t *out); size_t test__struct__pack_to_buffer (const Test__Struct *message, ProtobufCBuffer *buffer); Test__Struct * test__struct__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void test__struct__free_unpacked (Test__Struct *message, ProtobufCAllocator *allocator); /* Test__MapStruct methods */ void test__map_struct__init (Test__MapStruct *message); size_t test__map_struct__get_packed_size (const Test__MapStruct *message); size_t test__map_struct__pack (const Test__MapStruct *message, uint8_t *out); size_t test__map_struct__pack_to_buffer (const Test__MapStruct *message, ProtobufCBuffer *buffer); Test__MapStruct * test__map_struct__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void test__map_struct__free_unpacked (Test__MapStruct *message, ProtobufCAllocator *allocator); /* Test__RootMessage__FMapInt32Entry methods */ void test__root_message__fmap_int32_entry__init (Test__RootMessage__FMapInt32Entry *message); /* Test__RootMessage__FMapBoolEntry methods */ void test__root_message__fmap_bool_entry__init (Test__RootMessage__FMapBoolEntry *message); /* Test__RootMessage__FMapStringEntry methods */ void test__root_message__fmap_string_entry__init (Test__RootMessage__FMapStringEntry *message); /* Test__RootMessage__FMapFloatEntry methods */ void test__root_message__fmap_float_entry__init (Test__RootMessage__FMapFloatEntry *message); /* Test__RootMessage__FMapStructEntry methods */ void test__root_message__fmap_struct_entry__init (Test__RootMessage__FMapStructEntry *message); /* Test__RootMessage methods */ void test__root_message__init (Test__RootMessage *message); size_t test__root_message__get_packed_size (const Test__RootMessage *message); size_t test__root_message__pack (const Test__RootMessage *message, uint8_t *out); size_t test__root_message__pack_to_buffer (const Test__RootMessage *message, ProtobufCBuffer *buffer); Test__RootMessage * test__root_message__unpack (ProtobufCAllocator *allocator, size_t len, const uint8_t *data); void test__root_message__free_unpacked (Test__RootMessage *message, ProtobufCAllocator *allocator); /* --- per-message closures --- */ typedef void (*Test__Struct__NestedStruct_Closure) (const Test__Struct__NestedStruct *message, void *closure_data); typedef void (*Test__Struct_Closure) (const Test__Struct *message, void *closure_data); typedef void (*Test__MapStruct_Closure) (const Test__MapStruct *message, void *closure_data); typedef void (*Test__RootMessage__FMapInt32Entry_Closure) (const Test__RootMessage__FMapInt32Entry *message, void *closure_data); typedef void (*Test__RootMessage__FMapBoolEntry_Closure) (const Test__RootMessage__FMapBoolEntry *message, void *closure_data); typedef void (*Test__RootMessage__FMapStringEntry_Closure) (const Test__RootMessage__FMapStringEntry *message, void *closure_data); typedef void (*Test__RootMessage__FMapFloatEntry_Closure) (const Test__RootMessage__FMapFloatEntry *message, void *closure_data); typedef void (*Test__RootMessage__FMapStructEntry_Closure) (const Test__RootMessage__FMapStructEntry *message, void *closure_data); typedef void (*Test__RootMessage_Closure) (const Test__RootMessage *message, void *closure_data); /* --- services --- */ /* --- descriptors --- */ extern const ProtobufCMessageDescriptor test__struct__descriptor; extern const ProtobufCMessageDescriptor test__struct__nested_struct__descriptor; extern const ProtobufCEnumDescriptor test__struct__enum__descriptor; extern const ProtobufCMessageDescriptor test__map_struct__descriptor; extern const ProtobufCMessageDescriptor test__root_message__descriptor; extern const ProtobufCMessageDescriptor test__root_message__fmap_int32_entry__descriptor; extern const ProtobufCMessageDescriptor test__root_message__fmap_bool_entry__descriptor; extern const ProtobufCMessageDescriptor test__root_message__fmap_string_entry__descriptor; extern const ProtobufCMessageDescriptor test__root_message__fmap_float_entry__descriptor; extern const ProtobufCMessageDescriptor test__root_message__fmap_struct_entry__descriptor; PROTOBUF_C__END_DECLS #endif /* PROTOBUF_C_modules_2fpb_5ftests_2fpb_5ftests_2eproto__INCLUDED */ yara-4.5.3/libyara/modules/pb_tests/pb_tests.proto000066400000000000000000000031571501365277300223240ustar00rootroot00000000000000 syntax = "proto2"; package test; import "yara.proto"; option (yara.module_options) = { name : "pb_tests" root_message: "RootMessage"; }; message Struct { option (yara.message_options).name = "struct"; required string f_string = 1; enum Enum { option (yara.enum_options).name = "enum"; FIRST = 0; SECOND = 1; } optional Enum f_enum = 2; message NestedStruct { optional int32 f_int32 = 1; optional string f_string = 2; } optional NestedStruct f_nested_struct = 3; repeated NestedStruct f_nested_struct_array = 4; } message MapStruct { optional int32 f_int32 = 1; optional int64 f_int64 = 2; } message RootMessage { optional int32 f_int32 = 1; optional int64 f_int64 = 2; //optional uint32 f_uint32 = 3; // not supported //optional uint64 f_uint64 = 4; // not supported optional sint32 f_sint32 = 5; optional sint64 f_sint64 = 6; //optional fixed32 f_fixed32 = 7; // not supported //optional fixed64 f_fixed64 = 8; // not supported optional sfixed32 f_sfixed32 = 9; optional sfixed64 f_sfixed64 = 10; optional bool f_bool = 11; optional string f_string = 12; optional bytes f_bytes = 13; repeated Struct f_struct_array = 14; map f_map_int32 = 15; map f_map_bool = 16; map f_map_string = 17; map f_map_float = 18; map f_map_struct = 19; oneof f_oneof { string f_oneof_string = 20; MapStruct f_oneof_struct = 21; } optional string f_ignored = 22 [(yara.field_options).ignore = true]; optional string f_renamed = 23 [(yara.field_options).name = "f_yara_name"]; } yara-4.5.3/libyara/modules/pb_tests/yara.pb-c.h000066400000000000000000000002021501365277300213250ustar00rootroot00000000000000 /* * Empty header file generated by protoc-gen-yara because it is included from * .pb-c.h files generated by protoc-gen-c. */ yara-4.5.3/libyara/modules/pb_to_module.rst000066400000000000000000000017401501365277300207670ustar00rootroot00000000000000Generating a module from a Protocol Buffer [Protocol Buffers](https://developers.google.com/protocol-buffers) (protobufs) are Google's language-neutral, platform-idependent mechanism for serializing structured data. The first thing you need to do for using protobuf is defining your data structures, for example: message Employee { int32 id = 1; string name = 2; int32 age = 3 string email = 4; } Once you have defined your data structure, you use a protobuf compiler to automatically generate the code that will marshal/unmarshall the data structure into/from a bytes sequence. The protobuf compiler is able to generate code in multiple languages, including C/C++, Python, Java and Go. Now imagine that you can pass the marshalled data structure to YARA, and create rules based in that data. Like for example: import "vt_employee" rule virustotal_employee_under_25 { condition: vt_employee.age < 25 and vt_employee.email matches /*.@virustotal\.com/ } Neat, right? yara-4.5.3/libyara/modules/pe/000077500000000000000000000000001501365277300161675ustar00rootroot00000000000000yara-4.5.3/libyara/modules/pe/authenticode-parser/000077500000000000000000000000001501365277300221355ustar00rootroot00000000000000yara-4.5.3/libyara/modules/pe/authenticode-parser/authenticode.c000066400000000000000000000476171501365277300247740ustar00rootroot00000000000000/* Copyright (c) 2021 Avast Software 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "certificate.h" #include "countersignature.h" #include "helper.h" #include "structs.h" #define MAX_NESTED_COUNT 16 /* Moves signatures from src to dst, returns 0 on success, * else 1. If error occurs, arguments are unchanged */ static int authenticode_array_move(AuthenticodeArray* dst, AuthenticodeArray* src) { size_t newCount = dst->count + src->count; Authenticode** tmp = (Authenticode**)realloc(dst->signatures, newCount * sizeof(Authenticode*)); if (!tmp) return 1; dst->signatures = tmp; for (size_t i = 0; i < src->count; ++i) dst->signatures[i + dst->count] = src->signatures[i]; dst->count = newCount; free(src->signatures); src->signatures = NULL; src->count = 0; return 0; } static SpcIndirectDataContent* get_content(PKCS7* content) { if (!content) return NULL; if (OBJ_obj2nid(content->type) != OBJ_txt2nid(NID_spc_indirect_data)) return NULL; SpcIndirectDataContent* spcContent = SpcIndirectDataContent_new(); if (!spcContent) return NULL; int len = content->d.other->value.sequence->length; const uint8_t* data = content->d.other->value.sequence->data; d2i_SpcIndirectDataContent(&spcContent, &data, len); return spcContent; } static char* parse_program_name(ASN1_TYPE* spcAttr) { const uint8_t* spcData = spcAttr->value.sequence->data; int spcLen = spcAttr->value.sequence->length; SpcSpOpusInfo* spcInfo = d2i_SpcSpOpusInfo(NULL, &spcData, spcLen); if (!spcInfo) return NULL; char* result = NULL; if (spcInfo->programName) { uint8_t* data = NULL; /* Should be Windows UTF16..., try to convert it to UTF8 */ int nameLen = ASN1_STRING_to_UTF8(&data, spcInfo->programName->value.unicode); if (nameLen >= 0 && nameLen < spcLen) { result = (char*)malloc(nameLen + 1); if (result) { memcpy(result, data, nameLen); result[nameLen] = 0; } OPENSSL_free(data); } } SpcSpOpusInfo_free(spcInfo); return result; } static void parse_nested_authenticode(PKCS7_SIGNER_INFO* si, AuthenticodeArray* result) { STACK_OF(X509_ATTRIBUTE)* attrs = PKCS7_get_attributes(si); int idx = X509at_get_attr_by_NID(attrs, OBJ_txt2nid(NID_spc_nested_signature), -1); X509_ATTRIBUTE* attr = X509at_get_attr(attrs, idx); int attrCount = X509_ATTRIBUTE_count(attr); if (!attrCount) return; /* Limit the maximum amount of nested attributes to be safe from malformed samples */ attrCount = attrCount > MAX_NESTED_COUNT ? MAX_NESTED_COUNT : attrCount; for (int i = 0; i < attrCount; ++i) { ASN1_TYPE* nested = X509_ATTRIBUTE_get0_type(attr, i); if (nested == NULL) break; int len = nested->value.sequence->length; const uint8_t* data = nested->value.sequence->data; AuthenticodeArray* auth = authenticode_new(data, len); if (!auth) continue; authenticode_array_move(result, auth); authenticode_array_free(auth); } } static void parse_pkcs9_countersig(PKCS7* p7, Authenticode* auth) { PKCS7_SIGNER_INFO* si = sk_PKCS7_SIGNER_INFO_value(PKCS7_get_signer_info(p7), 0); STACK_OF(X509_ATTRIBUTE)* attrs = PKCS7_get_attributes(si); int idx = X509at_get_attr_by_NID(attrs, NID_pkcs9_countersignature, -1); X509_ATTRIBUTE* attr = X509at_get_attr(attrs, idx); int attrCount = X509_ATTRIBUTE_count(attr); if (!attrCount) return; /* Limit the maximum amount of nested attributes to be safe from malformed samples */ attrCount = attrCount > MAX_NESTED_COUNT ? MAX_NESTED_COUNT : attrCount; for (int i = 0; i < attrCount; ++i) { ASN1_TYPE* nested = X509_ATTRIBUTE_get0_type(attr, i); if (nested == NULL) break; int len = nested->value.sequence->length; const uint8_t* data = nested->value.sequence->data; Countersignature* sig = pkcs9_countersig_new(data, len, p7->d.sign->cert, si->enc_digest); if (!sig) continue; countersignature_array_insert(auth->countersigs, sig); } } static void parse_ms_countersig(PKCS7* p7, Authenticode* auth) { PKCS7_SIGNER_INFO* si = sk_PKCS7_SIGNER_INFO_value(PKCS7_get_signer_info(p7), 0); STACK_OF(X509_ATTRIBUTE)* attrs = PKCS7_get_attributes(si); int idx = X509at_get_attr_by_NID(attrs, OBJ_txt2nid(NID_spc_ms_countersignature), -1); X509_ATTRIBUTE* attr = X509at_get_attr(attrs, idx); int attrCount = X509_ATTRIBUTE_count(attr); if (!attrCount) return; /* Limit the maximum amount of nested attributes to be safe from malformed samples */ attrCount = attrCount > MAX_NESTED_COUNT ? MAX_NESTED_COUNT : attrCount; for (int i = 0; i < attrCount; ++i) { ASN1_TYPE* nested = X509_ATTRIBUTE_get0_type(attr, i); if (nested == NULL) break; int len = nested->value.sequence->length; const uint8_t* data = nested->value.sequence->data; Countersignature* csig = ms_countersig_new(data, len, si->enc_digest); if (!csig) return; countersignature_array_insert(auth->countersigs, csig); /* Because MS TimeStamp countersignature has it's own SET of certificates * extract it back into parent signature for consistency with PKCS9 */ certificate_array_append(auth->certs, csig->certs); } } static bool authenticode_verify(PKCS7* p7, PKCS7_SIGNER_INFO* si, X509* signCert) { const uint8_t* contentData = p7->d.sign->contents->d.other->value.sequence->data; long contentLen = p7->d.sign->contents->d.other->value.sequence->length; uint64_t version = 0; ASN1_INTEGER_get_uint64(&version, p7->d.sign->version); if (version == 1) { /* Move the pointer to the actual contents - skip OID and length */ int pclass = 0, ptag = 0; ASN1_get_object(&contentData, &contentLen, &ptag, &pclass, contentLen); } BIO* contentBio = BIO_new_mem_buf(contentData, contentLen); /* Create `digest` type BIO to calculate content digest for verification */ BIO* p7bio = PKCS7_dataInit(p7, contentBio); char buf[4096]; /* We now have to 'read' from p7bio to calculate content digest */ while (BIO_read(p7bio, buf, sizeof(buf)) > 0) continue; /* Pass it to the PKCS7_signatureVerify, to do the hard work for us */ bool isValid = PKCS7_signatureVerify(p7bio, p7, si, signCert) == 1; BIO_free_all(p7bio); return isValid; } /* Creates all the Authenticode objects so we can parse them with OpenSSL, is not thread-safe, needs * to be called once before any multi-threading environmentt - * https://github.com/openssl/openssl/issues/13524 */ void initialize_authenticode_parser() { OBJ_create("1.3.6.1.4.1.311.2.1.12", "spcSpOpusInfo", "SPC_SP_OPUS_INFO_OBJID"); OBJ_create("1.3.6.1.4.1.311.3.3.1", "spcMsCountersignature", "SPC_MICROSOFT_COUNTERSIGNATURE"); OBJ_create("1.3.6.1.4.1.311.2.4.1", "spcNestedSignature", "SPC_NESTED_SIGNATUREs"); OBJ_create("1.3.6.1.4.1.311.2.1.4", "spcIndirectData", "SPC_INDIRECT_DATA"); } /* Return array of Authenticode signatures stored in the data, there can be multiple * of signatures as Authenticode signatures are often nested through unauth attributes */ AuthenticodeArray* authenticode_new(const uint8_t* data, int32_t len) { if (!data || len <= 0) return NULL; AuthenticodeArray* result = (AuthenticodeArray*)calloc(1, sizeof(*result)); if (!result) return NULL; result->signatures = (Authenticode**)malloc(sizeof(Authenticode*)); if (!result->signatures) { free(result); return NULL; } Authenticode* auth = (Authenticode*)calloc(1, sizeof(*auth)); if (!auth) { free(result->signatures); free(result); return NULL; } result->count = 1; result->signatures[0] = auth; /* Let openssl parse the PKCS7 structure */ PKCS7* p7 = d2i_PKCS7(NULL, &data, len); if (!p7) { auth->verify_flags = AUTHENTICODE_VFY_CANT_PARSE; goto end; } /* We expect SignedData type of PKCS7 */ if (!PKCS7_type_is_signed(p7) || !p7->d.sign) { auth->verify_flags = AUTHENTICODE_VFY_WRONG_PKCS7_TYPE; goto end; } PKCS7_SIGNED* p7data = p7->d.sign; uint64_t version = 0; if (ASN1_INTEGER_get_uint64(&version, p7data->version)) auth->version = version; STACK_OF(X509)* certs = p7data->cert; auth->certs = certificate_array_new(sk_X509_num(certs)); if (!auth->certs) { auth->verify_flags = AUTHENTICODE_VFY_INTERNAL_ERROR; goto end; } parse_x509_certificates(certs, auth->certs); /* Get Signature content that contains the message digest and it's algorithm */ SpcIndirectDataContent* dataContent = get_content(p7data->contents); if (!dataContent) { auth->verify_flags = AUTHENTICODE_VFY_BAD_CONTENT; goto end; } DigestInfo* messageDigest = dataContent->messageDigest; int digestnid = OBJ_obj2nid(messageDigest->digestAlgorithm->algorithm); auth->digest_alg = strdup(OBJ_nid2ln(digestnid)); int digestLen = messageDigest->digest->length; const uint8_t* digestData = messageDigest->digest->data; byte_array_init(&auth->digest, digestData, digestLen); SpcIndirectDataContent_free(dataContent); Signer* signer = (Signer*)calloc(1, sizeof(Signer)); if (!signer) { auth->verify_flags = AUTHENTICODE_VFY_INTERNAL_ERROR; goto end; } auth->signer = signer; /* Authenticode is supposed to have only one SignerInfo value * that contains all information for actual signing purposes * and nested signatures or countersignatures */ PKCS7_SIGNER_INFO* si = sk_PKCS7_SIGNER_INFO_value(PKCS7_get_signer_info(p7), 0); if (!si) { auth->verify_flags = AUTHENTICODE_VFY_NO_SIGNER_INFO; goto end; } auth->countersigs = (CountersignatureArray*)calloc(1, sizeof(CountersignatureArray)); if (!auth->countersigs) { auth->verify_flags = AUTHENTICODE_VFY_INTERNAL_ERROR; goto end; } /* Authenticode can contain SET of nested Authenticode signatures * and countersignatures in unauthenticated attributes */ parse_nested_authenticode(si, result); parse_pkcs9_countersig(p7, auth); parse_ms_countersig(p7, auth); /* Get the signing certificate for the first SignerInfo */ STACK_OF(X509)* signCertStack = PKCS7_get0_signers(p7, certs, 0); X509* signCert = sk_X509_value(signCertStack, 0); if (!signCert) { auth->verify_flags = AUTHENTICODE_VFY_NO_SIGNER_CERT; sk_X509_free(signCertStack); goto end; } sk_X509_free(signCertStack); signer->chain = parse_signer_chain(signCert, certs); /* Get the Signers digest of Authenticode content */ ASN1_TYPE* digest = PKCS7_get_signed_attribute(si, NID_pkcs9_messageDigest); if (!digest) { auth->verify_flags = AUTHENTICODE_VFY_DIGEST_MISSING; goto end; } digestnid = OBJ_obj2nid(si->digest_alg->algorithm); signer->digest_alg = strdup(OBJ_nid2ln(digestnid)); digestLen = digest->value.asn1_string->length; digestData = digest->value.asn1_string->data; byte_array_init(&signer->digest, digestData, digestLen); /* Authenticode stores optional programName in non-optional SpcSpOpusInfo attribute */ ASN1_TYPE* spcInfo = PKCS7_get_signed_attribute(si, OBJ_txt2nid(NID_spc_info)); if (spcInfo) signer->program_name = parse_program_name(spcInfo); /* If we got to this point, we got all we need to start verifying */ bool isValid = authenticode_verify(p7, si, signCert); if (!isValid) auth->verify_flags = AUTHENTICODE_VFY_INVALID; end: PKCS7_free(p7); return result; } static int authenticode_digest( const EVP_MD* md, const uint8_t* pe_data, uint32_t pe_hdr_offset, bool is_64bit, uint32_t cert_table_addr, uint8_t* digest) { uint32_t buffer_size = 0xFFFF; uint8_t* buffer = (uint8_t*)malloc(buffer_size); /* BIO with the file data */ BIO* bio = BIO_new_mem_buf(pe_data, cert_table_addr); EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); if (!buffer || !bio || !mdctx) goto error; if (!EVP_DigestInit(mdctx, md)) goto error; /* Calculate size of the space between file start and PE header */ /* Checksum starts at 0x58th byte of the header */ uint32_t pe_checksum_offset = pe_hdr_offset + 0x58; /* Space between DOS and PE header could have arbitrary amount of data, read in chunks */ uint32_t fpos = 0; while (fpos < pe_checksum_offset) { uint32_t len_to_read = pe_checksum_offset - fpos; if (len_to_read > buffer_size) len_to_read = buffer_size; int rlen = BIO_read(bio, buffer, len_to_read); if (rlen <= 0) goto error; if (!EVP_DigestUpdate(mdctx, buffer, rlen)) goto error; fpos += rlen; } /* Skip the checksum */ if (BIO_read(bio, buffer, 4) <= 0) goto error; /* 64bit PE file is larger than 32bit */ uint32_t pe64_extra = is_64bit ? 16 : 0; /* Read up to certificate table*/ uint32_t cert_table_offset = 0x3c + pe64_extra; if (BIO_read(bio, buffer, cert_table_offset) <= 0) goto error; if (!EVP_DigestUpdate(mdctx, buffer, cert_table_offset)) goto error; /* Skip certificate table */ if (BIO_read(bio, buffer, 8) <= 0) goto error; /* PE header with check sum + checksum + cert table offset + cert table len */ fpos = pe_checksum_offset + 4 + cert_table_offset + 8; /* Hash everything up to the signature (assuming signature is stored in the * end of the file) */ /* Read chunks of the file in case the file is large */ while (fpos < cert_table_addr) { uint32_t len_to_read = cert_table_addr - fpos; if (len_to_read > buffer_size) len_to_read = buffer_size; int rlen = BIO_read(bio, buffer, len_to_read); if (rlen <= 0) goto error; if (!EVP_DigestUpdate(mdctx, buffer, rlen)) goto error; fpos += rlen; } /* Calculate the digest, write it into digest */ if (!EVP_DigestFinal(mdctx, digest, NULL)) goto error; EVP_MD_CTX_free(mdctx); BIO_free_all(bio); free(buffer); return 0; error: EVP_MD_CTX_free(mdctx); BIO_free_all(bio); free(buffer); return 1; } AuthenticodeArray* parse_authenticode(const uint8_t* pe_data, uint64_t pe_len) { const uint64_t dos_hdr_size = 0x40; if (pe_len < dos_hdr_size) return NULL; /* Check if it has DOS signature, so we don't parse random gibberish */ uint8_t dos_prefix[] = {0x4d, 0x5a}; if (memcmp(pe_data, dos_prefix, sizeof(dos_prefix)) != 0) return NULL; /* offset to pointer in DOS header, that points to PE header */ const int pe_hdr_ptr_offset = 0x3c; /* Read the PE offset */ uint32_t pe_offset = letoh32(*(uint32_t*)(pe_data + pe_hdr_ptr_offset)); /* Offset to Magic, to know the PE class (32/64bit) */ uint32_t magic_addr = pe_offset + 0x18; if (pe_len < magic_addr + sizeof(uint16_t)) return NULL; /* Read the magic and check if we have 64bit PE */ uint16_t magic = letoh16(*(uint16_t*)(pe_data + magic_addr)); bool is_64bit = magic == 0x20b; /* If PE is 64bit, header is 16 bytes larger */ uint8_t pe64_extra = is_64bit ? 16 : 0; /* Calculate offset to certificate table directory */ uint32_t pe_cert_table_addr = pe_offset + pe64_extra + 0x98; if (pe_len < pe_cert_table_addr + 2 * sizeof(uint32_t)) return NULL; /* Use 64bit type due to the potential overflow in crafted binaries */ uint64_t cert_addr = letoh32(*(uint32_t*)(pe_data + pe_cert_table_addr)); uint64_t cert_len = letoh32(*(uint32_t*)(pe_data + pe_cert_table_addr + 4)); /* we need atleast 8 bytes to read dwLength, revision and certType */ if (cert_len < 8 || pe_len < cert_addr + 8) return NULL; uint32_t dwLength = letoh32(*(uint32_t*)(pe_data + cert_addr)); if (pe_len < cert_addr + dwLength) return NULL; /* dwLength = offsetof(WIN_CERTIFICATE, bCertificate) + (size of the variable-length binary * array contained within bCertificate) */ AuthenticodeArray* auth_array = authenticode_new(pe_data + cert_addr + 0x8, dwLength - 0x8); if (!auth_array) return NULL; /* Compare valid signatures file digests to actual file digest, to complete verification */ for (size_t i = 0; i < auth_array->count; ++i) { Authenticode* sig = auth_array->signatures[i]; const EVP_MD* md = EVP_get_digestbyname(sig->digest_alg); if (!md || !sig->digest.len || !sig->digest.data) { /* If there is an verification error, keep the first error */ if (sig->verify_flags == AUTHENTICODE_VFY_VALID) sig->verify_flags = AUTHENTICODE_VFY_UNKNOWN_ALGORITHM; continue; } #if OPENSSL_VERSION_NUMBER >= 0x3000000fL int mdlen = EVP_MD_get_size(md); #else int mdlen = EVP_MD_size(md); #endif sig->file_digest.len = mdlen; sig->file_digest.data = (uint8_t*)malloc(mdlen); if (!sig->file_digest.data) continue; if (authenticode_digest( md, pe_data, pe_offset, is_64bit, cert_addr, sig->file_digest.data)) { /* If there is an verification error, keep the first error */ if (sig->verify_flags == AUTHENTICODE_VFY_VALID) sig->verify_flags = AUTHENTICODE_VFY_INTERNAL_ERROR; break; } /* Complete the verification */ if (memcmp(sig->file_digest.data, sig->digest.data, mdlen) != 0) sig->verify_flags = AUTHENTICODE_VFY_WRONG_FILE_DIGEST; } return auth_array; } static void signer_free(Signer* si) { if (si) { free(si->digest.data); free(si->digest_alg); free(si->program_name); certificate_array_free(si->chain); free(si); } } static void authenticode_free(Authenticode* auth) { if (auth) { free(auth->digest.data); free(auth->file_digest.data); free(auth->digest_alg); signer_free(auth->signer); certificate_array_free(auth->certs); countersignature_array_free(auth->countersigs); free(auth); } } void authenticode_array_free(AuthenticodeArray* arr) { if (arr) { for (size_t i = 0; i < arr->count; ++i) { authenticode_free(arr->signatures[i]); } free(arr->signatures); free(arr); } } yara-4.5.3/libyara/modules/pe/authenticode-parser/certificate.c000066400000000000000000000413211501365277300245640ustar00rootroot00000000000000/* Copyright (c) 2021 Avast Software 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 "certificate.h" #include #include #include #include #include #include #include #include "helper.h" #if OPENSSL_VERSION_NUMBER >= 0x3000000fL /* Removes any escaping \/ -> / that is happening with oneline() functions from OpenSSL 3.0 */ static void parse_oneline_string(char* string) { size_t len = strlen(string); char* tmp = string; while (true) { char* ptr = strstr(tmp, "\\/"); if (!ptr) break; memmove(ptr, ptr + 1, strlen(ptr + 1)); tmp = ptr + 1; len--; } string[len] = 0; } #endif static void parse_name_attributes(X509_NAME* raw, Attributes* attr) { if (!raw || !attr) return; int entryCount = X509_NAME_entry_count(raw); for (int i = entryCount - 1; i >= 0; --i) { X509_NAME_ENTRY* entryName = X509_NAME_get_entry(raw, i); ASN1_STRING* asn1String = X509_NAME_ENTRY_get_data(entryName); const char* key = OBJ_nid2sn(OBJ_obj2nid(X509_NAME_ENTRY_get_object(entryName))); ByteArray array = {0}; if (byte_array_init(&array, asn1String->data, asn1String->length) == -1) break; if (strcmp(key, "C") == 0 && !attr->country.data) attr->country = array; else if (strcmp(key, "O") == 0 && !attr->organization.data) attr->organization = array; else if (strcmp(key, "OU") == 0 && !attr->organizationalUnit.data) attr->organizationalUnit = array; else if (strcmp(key, "dnQualifier") == 0 && !attr->nameQualifier.data) attr->nameQualifier = array; else if (strcmp(key, "ST") == 0 && !attr->state.data) attr->state = array; else if (strcmp(key, "CN") == 0 && !attr->commonName.data) attr->commonName = array; else if (strcmp(key, "serialNumber") == 0 && !attr->serialNumber.data) attr->serialNumber = array; else if (strcmp(key, "L") == 0 && !attr->locality.data) attr->locality = array; else if (strcmp(key, "title") == 0 && !attr->title.data) attr->title = array; else if (strcmp(key, "SN") == 0 && !attr->surname.data) attr->surname = array; else if (strcmp(key, "GN") == 0 && !attr->givenName.data) attr->givenName = array; else if (strcmp(key, "initials") == 0 && !attr->initials.data) attr->initials = array; else if (strcmp(key, "pseudonym") == 0 && !attr->pseudonym.data) attr->pseudonym = array; else if (strcmp(key, "generationQualifier") == 0 && !attr->generationQualifier.data) attr->generationQualifier = array; else if (strcmp(key, "emailAddress") == 0 && !attr->emailAddress.data) attr->emailAddress = array; else free(array.data); } } /* Reconstructs signers certificate chain */ CertificateArray* parse_signer_chain(X509* signCert, STACK_OF(X509) * certs) { if (!signCert || !certs) return NULL; X509_STORE* store = X509_STORE_new(); if (!store) return NULL; X509_STORE_CTX* storeCtx = X509_STORE_CTX_new(); if (!storeCtx) { X509_STORE_CTX_free(storeCtx); return NULL; } X509_STORE_CTX_init(storeCtx, store, signCert, certs); /* I can't find ability to use this function for static verification with missing trust anchors, * because roots are generally not part of the PKCS7 signatures, so the return value is * currently ignored and the function is only used to build the certificate chain */ X509_verify_cert(storeCtx); STACK_OF(X509)* chain = X509_STORE_CTX_get_chain(storeCtx); int certCount = sk_X509_num(chain); CertificateArray* result = (CertificateArray*)calloc(1, sizeof(*result)); if (!result) goto error; result->certs = (Certificate**)calloc(certCount, sizeof(Certificate*)); if (!result->certs) goto error; /* Convert each certificate to internal representation */ for (int i = 0; i < certCount; ++i) { Certificate* cert = certificate_new(sk_X509_value(chain, i)); if (!cert) goto error; result->certs[i] = cert; result->count++; } X509_STORE_free(store); X509_STORE_CTX_free(storeCtx); return result; error: /* In case of error, return nothing */ if (result) { for (size_t i = 0; i < result->count; ++i) { certificate_free(result->certs[i]); } free(result->certs); free(result); } X509_STORE_free(store); X509_STORE_CTX_free(storeCtx); return NULL; } /* Taken from YARA for compatibility */ static char* integer_to_serial(ASN1_INTEGER* serial) { int bytes = i2d_ASN1_INTEGER(serial, NULL); char* res = NULL; /* According to X.509 specification the maximum length for the * serial number is 20 octets. Add two bytes to account for * DER type and length information. */ if (bytes < 2 || bytes > 22) return NULL; /* Now that we know the size of the serial number allocate enough * space to hold it, and use i2d_ASN1_INTEGER() one last time to * hold it in the allocated buffer. */ uint8_t* serial_der = (uint8_t*)malloc(bytes); if (!serial_der) return NULL; uint8_t* serial_bytes; bytes = i2d_ASN1_INTEGER(serial, &serial_der); /* i2d_ASN1_INTEGER() moves the pointer as it writes into serial_bytes. Move it back. */ serial_der -= bytes; /* Skip over DER type, length information */ serial_bytes = serial_der + 2; bytes -= 2; /* Also allocate space to hold the "common" string format: * 00:01:02:03:04... * * For each byte in the serial to convert to hexlified format we * need three bytes, two for the byte itself and one for colon. * The last one doesn't have the colon, but the extra byte is used * for the NULL terminator. */ res = (char*)malloc(bytes * 3); if (res) { for (int i = 0; i < bytes; i++) { /* Don't put the colon on the last one. */ if (i < bytes - 1) snprintf(res + 3 * i, 4, "%02x:", serial_bytes[i]); else snprintf(res + 3 * i, 3, "%02x", serial_bytes[i]); } } free(serial_der); return (char*)res; } /* Converts the pubkey to pem, which is just * Base64 encoding of the DER representation */ static char* pubkey_to_pem(EVP_PKEY* pubkey) { uint8_t* der = NULL; int len = i2d_PUBKEY(pubkey, &der); /* Convert to DER */ if (len <= 0) return NULL; /* Approximate the result length (padding, newlines, 4 out bytes for every 3 in) */ uint8_t* result = (uint8_t*)malloc(len * 3 / 2); if (!result) { OPENSSL_free(der); return NULL; } /* Base64 encode the DER data */ EVP_ENCODE_CTX* ctx = EVP_ENCODE_CTX_new(); if (!ctx) { OPENSSL_free(der); free(result); return NULL; } int resultLen = 0; int tmp = 0; EVP_EncodeInit(ctx); EVP_EncodeUpdate(ctx, result, &tmp, der, len); resultLen += tmp; EVP_EncodeFinal(ctx, result + resultLen, &tmp); resultLen += tmp; EVP_ENCODE_CTX_free(ctx); OPENSSL_free(der); /* Remove all newlines from the encoded base64 * resultLen is excluding NULL terminator */ for (int i = 0; result[i] != 0; i++) { if (result[i] == '\n') memmove(result + i, result + i + 1, resultLen - i); } return (char*)result; } Certificate* certificate_new(X509* x509) { Certificate* result = (Certificate*)calloc(1, sizeof(*result)); if (!result) return NULL; /* Calculate SHA1 and SHA256 digests of the X509 structure */ result->sha1.data = (uint8_t*)malloc(SHA_DIGEST_LENGTH); if (result->sha1.data) { X509_digest(x509, EVP_sha1(), result->sha1.data, NULL); result->sha1.len = SHA_DIGEST_LENGTH; } result->sha256.data = (uint8_t*)malloc(SHA256_DIGEST_LENGTH); if (result->sha256.data) { X509_digest(x509, EVP_sha256(), result->sha256.data, NULL); result->sha256.len = SHA256_DIGEST_LENGTH; } /* 256 bytes should be enough for any name */ char buffer[256]; /* X509_NAME_online is deprecated and shouldn't be used per OpenSSL docs * but we want to comply with existing YARA code */ X509_NAME* issuerName = X509_get_issuer_name(x509); X509_NAME_oneline(issuerName, buffer, sizeof(buffer)); result->issuer = strdup(buffer); /* This is a little ugly hack for 3.0 compatibility */ #if OPENSSL_VERSION_NUMBER >= 0x3000000fL parse_oneline_string(result->issuer); #endif X509_NAME* subjectName = X509_get_subject_name(x509); X509_NAME_oneline(subjectName, buffer, sizeof(buffer)); result->subject = strdup(buffer); #if OPENSSL_VERSION_NUMBER >= 0x3000000fL parse_oneline_string(result->subject); #endif parse_name_attributes(issuerName, &result->issuer_attrs); parse_name_attributes(subjectName, &result->subject_attrs); result->version = X509_get_version(x509); result->serial = integer_to_serial(X509_get_serialNumber(x509)); result->not_after = ASN1_TIME_to_int64_t(X509_get0_notAfter(x509)); result->not_before = ASN1_TIME_to_int64_t(X509_get0_notBefore(x509)); int sig_nid = X509_get_signature_nid(x509); result->sig_alg = strdup(OBJ_nid2ln(sig_nid)); OBJ_obj2txt(buffer, sizeof(buffer), OBJ_nid2obj(sig_nid), 1); result->sig_alg_oid = strdup(buffer); EVP_PKEY* pkey = X509_get0_pubkey(x509); if (pkey) { result->key = pubkey_to_pem(pkey); #if OPENSSL_VERSION_NUMBER >= 0x3000000fL result->key_alg = strdup(OBJ_nid2sn(EVP_PKEY_get_base_id(pkey))); #else result->key_alg = strdup(OBJ_nid2sn(EVP_PKEY_base_id(pkey))); #endif } return result; } void attributes_copy(Attributes* dst, Attributes* src) { byte_array_init(&dst->country, src->country.data, src->country.len); byte_array_init(&dst->organization, src->organization.data, src->organization.len); byte_array_init( &dst->organizationalUnit, src->organizationalUnit.data, src->organizationalUnit.len); byte_array_init(&dst->nameQualifier, src->nameQualifier.data, src->nameQualifier.len); byte_array_init(&dst->state, src->state.data, src->state.len); byte_array_init(&dst->commonName, src->commonName.data, src->commonName.len); byte_array_init(&dst->serialNumber, src->serialNumber.data, src->serialNumber.len); byte_array_init(&dst->locality, src->locality.data, src->locality.len); byte_array_init(&dst->title, src->title.data, src->title.len); byte_array_init(&dst->surname, src->surname.data, src->surname.len); byte_array_init(&dst->givenName, src->givenName.data, src->givenName.len); byte_array_init(&dst->initials, src->initials.data, src->initials.len); byte_array_init(&dst->pseudonym, src->pseudonym.data, src->pseudonym.len); byte_array_init( &dst->generationQualifier, src->generationQualifier.data, src->generationQualifier.len); byte_array_init(&dst->emailAddress, src->emailAddress.data, src->emailAddress.len); } /* Parses X509* certs into internal representation and inserts into CertificateArray * Array is assumed to have enough space to hold all certificates storted in the STACK */ void parse_x509_certificates(const STACK_OF(X509) * certs, CertificateArray* result) { int certCount = sk_X509_num(certs); int i = 0; for (; i < certCount; ++i) { Certificate* cert = certificate_new(sk_X509_value(certs, i)); if (!cert) break; /* Write to the result */ result->certs[i] = cert; } result->count = i; } /* Creates deep copy of a certificate */ Certificate* certificate_copy(Certificate* cert) { if (!cert) return NULL; Certificate* result = (Certificate*)calloc(1, sizeof(*result)); if (!result) return NULL; result->version = cert->version; result->issuer = cert->issuer ? strdup(cert->issuer) : NULL; result->subject = cert->subject ? strdup(cert->subject) : NULL; result->serial = cert->serial ? strdup(cert->serial) : NULL; result->not_after = cert->not_after; result->not_before = cert->not_before; result->sig_alg = cert->sig_alg ? strdup(cert->sig_alg) : NULL; result->sig_alg_oid = cert->sig_alg_oid ? strdup(cert->sig_alg_oid) : NULL; result->key_alg = cert->key_alg ? strdup(cert->key_alg) : NULL; result->key = cert->key ? strdup(cert->key) : NULL; byte_array_init(&result->sha1, cert->sha1.data, cert->sha1.len); byte_array_init(&result->sha256, cert->sha256.data, cert->sha256.len); attributes_copy(&result->issuer_attrs, &cert->issuer_attrs); attributes_copy(&result->subject_attrs, &cert->subject_attrs); return result; } /* Moves certificates from src to dst, returns 0 on success, * else 1. If error occurs, arguments are unchanged */ int certificate_array_move(CertificateArray* dst, CertificateArray* src) { if (!dst || !src) return 1; if (!src->certs || !src->count) return 0; size_t newCount = dst->count + src->count; Certificate** tmp = (Certificate**)realloc(dst->certs, newCount * sizeof(Certificate*)); if (!tmp) return 1; dst->certs = tmp; for (size_t i = 0; i < src->count; ++i) dst->certs[i + dst->count] = src->certs[i]; dst->count = newCount; free(src->certs); src->certs = NULL; src->count = 0; return 0; } /* Copies certificates from src and appends to dst, returns 0 on success, * else 1. If error occurs, arguments are unchanged */ int certificate_array_append(CertificateArray* dst, CertificateArray* src) { if (!dst || !src) return 1; if (!src->certs || !src->count) return 0; size_t newCount = dst->count + src->count; Certificate** tmp = (Certificate**)realloc(dst->certs, newCount * sizeof(Certificate*)); if (!tmp) return 1; dst->certs = tmp; for (size_t i = 0; i < src->count; ++i) dst->certs[i + dst->count] = certificate_copy(src->certs[i]); dst->count = newCount; return 0; } /* Allocates empty certificate array with reserved space for certCount certs */ CertificateArray* certificate_array_new(int certCount) { CertificateArray* arr = (CertificateArray*)malloc(sizeof(*arr)); if (!arr) return NULL; arr->certs = (Certificate**)malloc(sizeof(Certificate*) * certCount); if (!arr->certs) { free(arr); return NULL; } arr->count = certCount; return arr; } static void certificate_attributes_free(Attributes attrs) { free(attrs.country.data); free(attrs.organization.data); free(attrs.organizationalUnit.data); free(attrs.nameQualifier.data); free(attrs.state.data); free(attrs.commonName.data); free(attrs.serialNumber.data); free(attrs.locality.data); free(attrs.title.data); free(attrs.surname.data); free(attrs.givenName.data); free(attrs.initials.data); free(attrs.pseudonym.data); free(attrs.generationQualifier.data); free(attrs.emailAddress.data); } void certificate_free(Certificate* cert) { if (cert) { free(cert->issuer); free(cert->subject); free(cert->sig_alg); free(cert->sig_alg_oid); free(cert->key_alg); free(cert->key); free(cert->sha1.data); free(cert->sha256.data); free(cert->serial); certificate_attributes_free(cert->issuer_attrs); certificate_attributes_free(cert->subject_attrs); free(cert); } } void certificate_array_free(CertificateArray* arr) { if (arr) { for (size_t i = 0; i < arr->count; ++i) { certificate_free(arr->certs[i]); } free(arr->certs); free(arr); } } yara-4.5.3/libyara/modules/pe/authenticode-parser/certificate.h000066400000000000000000000035061501365277300245740ustar00rootroot00000000000000/* Copyright (c) 2021 Avast Software 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 AUTHENTICODE_PARSER_CERTIFICATE_H #define AUTHENTICODE_PARSER_CERTIFICATE_H #include #include #ifdef __cplusplus extern "C" { #endif Certificate* certificate_new(X509* x509); Certificate* certificate_copy(Certificate* cert); void certificate_free(Certificate* cert); void parse_x509_certificates(const STACK_OF(X509) * certs, CertificateArray* result); CertificateArray* parse_signer_chain(X509* signer_cert, STACK_OF(X509) * certs); int certificate_array_move(CertificateArray* dst, CertificateArray* src); int certificate_array_append(CertificateArray* dst, CertificateArray* src); CertificateArray* certificate_array_new(int certCount); void certificate_array_free(CertificateArray* arr); #ifdef __cplusplus } #endif #endif yara-4.5.3/libyara/modules/pe/authenticode-parser/countersignature.c000066400000000000000000000527001501365277300257060ustar00rootroot00000000000000/* Copyright (c) 2021 Avast Software 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 "countersignature.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "certificate.h" #include "helper.h" #include "structs.h" struct CountersignatureImplStruct; typedef TS_TST_INFO* get_ts_tst_info_func(struct CountersignatureImplStruct*); typedef STACK_OF(X509) * get_signers_func(struct CountersignatureImplStruct*); typedef STACK_OF(X509) * get_certs_func(struct CountersignatureImplStruct*); typedef int verify_digest_func(struct CountersignatureImplStruct*, uint8_t* digest, size_t digest_size); typedef BIO* verify_signature_init_func(struct CountersignatureImplStruct*); typedef int verify_signature_finish_func(struct CountersignatureImplStruct*, BIO* bio, X509* signer); #define IMPL_FUNC_NAME(func, type) ms_countersig_impl_##func##_##type##_ #define DECLARE_FUNCS(type) \ get_ts_tst_info_func IMPL_FUNC_NAME(get_ts_tst_info, type); \ get_signers_func IMPL_FUNC_NAME(get_signers, type); \ get_certs_func IMPL_FUNC_NAME(get_certs, type); \ verify_digest_func IMPL_FUNC_NAME(verify_digest, type); \ verify_signature_init_func IMPL_FUNC_NAME(verify_signature_init, type); \ verify_signature_finish_func IMPL_FUNC_NAME(verify_signature_finish, type); DECLARE_FUNCS(pkcs7) DECLARE_FUNCS(cms) typedef struct { get_ts_tst_info_func* get_ts_tst_info; get_signers_func* get_signers; get_certs_func* get_certs; verify_digest_func* verify_digest; verify_signature_init_func* verify_signature_init; verify_signature_finish_func* verify_signature_finish; } CountersignatureImplFuncs; #define FUNC_ARRAY_NAME_FOR_IMPL(type) countersig_impl_funcs_##type##_ #define FUNC_ARRAY_FOR_IMPL(type) \ static const CountersignatureImplFuncs FUNC_ARRAY_NAME_FOR_IMPL(type) = { \ &IMPL_FUNC_NAME(get_ts_tst_info, type), \ &IMPL_FUNC_NAME(get_signers, type), \ &IMPL_FUNC_NAME(get_certs, type), \ &IMPL_FUNC_NAME(verify_digest, type), \ &IMPL_FUNC_NAME(verify_signature_init, type), \ &IMPL_FUNC_NAME(verify_signature_finish, type), \ }; FUNC_ARRAY_FOR_IMPL(pkcs7) FUNC_ARRAY_FOR_IMPL(cms) typedef enum { CS_IMPL_PKCS7, CS_IMPL_CMS, } CountersignatureImplType; typedef struct CountersignatureImplStruct { CountersignatureImplType type; const CountersignatureImplFuncs* funcs; union { PKCS7* pkcs7; CMS_ContentInfo* cms; }; // this is here to serve as a cache for CMS because the only way to obtain // certs from CMS is to use CMS_get1_certs which leaves the deallocation // to the caller but it just complicates things if you need to remember to // deallocate also certs. This makes it easier if CountersignatureImpl itself // is an owner of this thing. STACK_OF(X509) * _certs; } CountersignatureImpl; Countersignature* pkcs9_countersig_new( const uint8_t* data, long size, STACK_OF(X509) * certs, ASN1_STRING* enc_digest) { Countersignature* result = (Countersignature*)calloc(1, sizeof(*result)); if (!result) return NULL; PKCS7_SIGNER_INFO* si = d2i_PKCS7_SIGNER_INFO(NULL, &data, size); if (!si) { result->verify_flags = COUNTERSIGNATURE_VFY_CANT_PARSE; return result; } int digestnid = OBJ_obj2nid(si->digest_alg->algorithm); result->digest_alg = strdup(OBJ_nid2ln(digestnid)); const ASN1_TYPE* sign_time = PKCS7_get_signed_attribute(si, NID_pkcs9_signingTime); if (!sign_time) { result->verify_flags = COUNTERSIGNATURE_VFY_TIME_MISSING; goto end; } result->sign_time = ASN1_TIME_to_int64_t(sign_time->value.utctime); X509* signCert = X509_find_by_issuer_and_serial( certs, si->issuer_and_serial->issuer, si->issuer_and_serial->serial); if (!signCert) { result->verify_flags = COUNTERSIGNATURE_VFY_NO_SIGNER_CERT; goto end; } /* PKCS9 stores certificates in the corresponding PKCS7 it countersigns */ result->chain = parse_signer_chain(signCert, certs); /* Get digest that corresponds to decrypted encrypted digest in signature */ ASN1_TYPE* messageDigest = PKCS7_get_signed_attribute(si, NID_pkcs9_messageDigest); if (!messageDigest) { result->verify_flags = COUNTERSIGNATURE_VFY_DIGEST_MISSING; goto end; } size_t digestLen = messageDigest->value.octet_string->length; if (!digestLen) { result->verify_flags = COUNTERSIGNATURE_VFY_DIGEST_MISSING; goto end; } const EVP_MD* md = EVP_get_digestbynid(digestnid); if (!md) { result->verify_flags = COUNTERSIGNATURE_VFY_UNKNOWN_ALGORITHM; goto end; } const uint8_t* digestData = messageDigest->value.octet_string->data; byte_array_init(&result->digest, digestData, digestLen); /* By this point we all necessary things for verification * Get DER representation of the authenticated attributes to calculate its * digest that should correspond with the one encrypted in SignerInfo */ uint8_t* authAttrsData = NULL; int authAttrsLen = ASN1_item_i2d( (ASN1_VALUE*)si->auth_attr, &authAttrsData, ASN1_ITEM_rptr(PKCS7_ATTR_VERIFY)); uint8_t calc_digest[EVP_MAX_MD_SIZE]; calculate_digest(md, authAttrsData, authAttrsLen, calc_digest); OPENSSL_free(authAttrsData); /* Get public key to decrypt encrypted digest of auth attrs */ EVP_PKEY* pkey = X509_get0_pubkey(signCert); EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(pkey, NULL); /* TODO try to get rid of hardcoded length bound */ size_t decLen = 65536; uint8_t* decData = (uint8_t*)malloc(decLen); if (!decData) { EVP_PKEY_CTX_free(ctx); result->verify_flags = COUNTERSIGNATURE_VFY_INTERNAL_ERROR; goto end; } uint8_t* encData = si->enc_digest->data; size_t encLen = si->enc_digest->length; /* Decrypt the encrypted digest */ EVP_PKEY_verify_recover_init(ctx); bool isDecrypted = EVP_PKEY_verify_recover(ctx, decData, &decLen, encData, encLen) == 1; EVP_PKEY_CTX_free(ctx); if (!isDecrypted) { free(decData); result->verify_flags = COUNTERSIGNATURE_VFY_CANT_DECRYPT_DIGEST; goto end; } /* compare the encrypted digest and calculated digest */ bool isValid = false; #if OPENSSL_VERSION_NUMBER >= 0x3000000fL size_t mdLen = EVP_MD_get_size(md); #else size_t mdLen = EVP_MD_size(md); #endif /* Sometimes signed data contains DER encoded DigestInfo structure which contains hash of * authenticated attributes (39c9d136f026a9ad18fb9f41a64f76dd8418e8de625dce5d3a372bd242fc5edd) * but other times it is just purely and I didn't find another way to distinguish it but only * based on the length of data we get. Found mention of this in openssl mailing list: * https://mta.openssl.org/pipermail/openssl-users/2015-September/002054.html */ if (mdLen == decLen) { isValid = !memcmp(calc_digest, decData, mdLen); } else { const uint8_t* data_ptr = decData; DigestInfo* digest_info = d2i_DigestInfo(NULL, &data_ptr, decLen); if (digest_info) { isValid = !memcmp(digest_info->digest->data, calc_digest, mdLen); DigestInfo_free(digest_info); } else { isValid = false; } } free(decData); if (!isValid) { result->verify_flags = COUNTERSIGNATURE_VFY_INVALID; goto end; } /* Now check the countersignature message-digest that should correspond * to Signatures encrypted digest it countersigns */ calculate_digest(md, enc_digest->data, enc_digest->length, calc_digest); /* Check if calculated one matches the stored one */ if (digestLen != mdLen || memcmp(calc_digest, digestData, mdLen) != 0) { result->verify_flags = COUNTERSIGNATURE_VFY_DOESNT_MATCH_SIGNATURE; goto end; } end: PKCS7_SIGNER_INFO_free(si); return result; } TS_TST_INFO* IMPL_FUNC_NAME(get_ts_tst_info, pkcs7)(CountersignatureImpl* impl) { assert(impl->type == CS_IMPL_PKCS7); return PKCS7_to_TS_TST_INFO(impl->pkcs7); } TS_TST_INFO* IMPL_FUNC_NAME(get_ts_tst_info, cms)(CountersignatureImpl* impl) { assert(impl->type == CS_IMPL_CMS); const ASN1_OBJECT* content_type = CMS_get0_eContentType(impl->cms); if (!content_type || OBJ_obj2nid(content_type) != NID_id_smime_ct_TSTInfo) { return NULL; } ASN1_OCTET_STRING** content = CMS_get0_content(impl->cms); if (!content || !*content) { return NULL; } const uint8_t* data = (*content)->data; TS_TST_INFO* ts_tst_info = d2i_TS_TST_INFO(NULL, &data, (*content)->length); if (!ts_tst_info) { return NULL; } return ts_tst_info; } STACK_OF(X509) * IMPL_FUNC_NAME(get_signers, pkcs7)(CountersignatureImpl* impl) { assert(impl->type == CS_IMPL_PKCS7); return PKCS7_get0_signers(impl->pkcs7, impl->pkcs7->d.sign->cert, 0); } STACK_OF(X509) * IMPL_FUNC_NAME(get_signers, cms)(CountersignatureImpl* impl) { assert(impl->type == CS_IMPL_CMS); STACK_OF(CMS_SignerInfo)* signer_infos = CMS_get0_SignerInfos(impl->cms); if (!signer_infos) { return NULL; } // Use our func points to cache the certs and don't create another copy STACK_OF(X509)* certs = impl->funcs->get_certs(impl); int si_count = sk_CMS_SignerInfo_num(signer_infos); int cert_count = certs ? sk_X509_num(certs) : 0; STACK_OF(X509)* result = sk_X509_new_null(); // PKCS7_get0_signers() lets us specify the certificate array and looks up signer certificate // there With CMS_ContentInfo, we don't have direct access to signer certificate, just all the // certificates The only thing we can do is to go through all signer infos and find those which // match some certificate in all certificates. It essentially simulates what // PKCS7_get0_signers() does. for (int i = 0; i < si_count; ++i) { CMS_SignerInfo* si = sk_CMS_SignerInfo_value(signer_infos, i); if (!si) { continue; } if (certs) { for (int j = 0; j < cert_count; ++j) { X509* cert = sk_X509_value(certs, j); if (!cert) { continue; } if (CMS_SignerInfo_cert_cmp(si, cert) == 0) { if (!sk_X509_push(result, cert)) { return NULL; } } } } } return result; } STACK_OF(X509) * IMPL_FUNC_NAME(get_certs, pkcs7)(CountersignatureImpl* impl) { assert(impl->type == CS_IMPL_PKCS7); return impl->pkcs7->d.sign->cert; } STACK_OF(X509) * IMPL_FUNC_NAME(get_certs, cms)(CountersignatureImpl* impl) { assert(impl->type == CS_IMPL_CMS); if (impl->_certs) { return impl->_certs; } impl->_certs = CMS_get1_certs(impl->cms); return impl->_certs; } int IMPL_FUNC_NAME(verify_digest, pkcs7)( CountersignatureImpl* impl, uint8_t* digest, size_t digest_size) { assert(impl->type == CS_IMPL_PKCS7); X509_STORE* store = X509_STORE_new(); TS_VERIFY_CTX* ctx = TS_VERIFY_CTX_new(); TS_VERIFY_CTX_set_flags(ctx, TS_VFY_VERSION | TS_VFY_IMPRINT); TS_VERIFY_CTX_set_store(ctx, store); #if OPENSSL_VERSION_NUMBER >= 0x3000000fL TS_VERIFY_CTX_set_certs(ctx, impl->funcs->get_certs(impl)); #else TS_VERIFY_CTS_set_certs(ctx, impl->funcs->get_certs(impl)); #endif TS_VERIFY_CTX_set_imprint(ctx, digest, digest_size); int result = TS_RESP_verify_token(ctx, impl->pkcs7); X509_STORE_free(store); OPENSSL_free(ctx); return result; } int IMPL_FUNC_NAME(verify_digest, cms)( CountersignatureImpl* impl, uint8_t* digest, size_t digest_size) { assert(impl->type == CS_IMPL_CMS); // This is essentially just reimplementation of TS_RESP_verify_token() from OpenSSL TS_TST_INFO* ts_tst_info = impl->funcs->get_ts_tst_info(impl); if (!ts_tst_info || TS_TST_INFO_get_version(ts_tst_info) != 1) { if (ts_tst_info) TS_TST_INFO_free(ts_tst_info); return 0; } TS_MSG_IMPRINT* ts_imprint = TS_TST_INFO_get_msg_imprint(ts_tst_info); if (!ts_imprint) { TS_TST_INFO_free(ts_tst_info); return 0; } ASN1_OCTET_STRING* ts_imprint_digest = TS_MSG_IMPRINT_get_msg(ts_imprint); if (!ts_imprint_digest) { TS_TST_INFO_free(ts_tst_info); return 0; } if (ts_imprint_digest->length != (int)digest_size || memcmp(ts_imprint_digest->data, digest, digest_size) != 0) { TS_TST_INFO_free(ts_tst_info); return 0; } TS_TST_INFO_free(ts_tst_info); return 1; } BIO* IMPL_FUNC_NAME(verify_signature_init, pkcs7)(CountersignatureImpl* impl) { assert(impl->type == CS_IMPL_PKCS7); return PKCS7_dataInit(impl->pkcs7, NULL); } BIO* IMPL_FUNC_NAME(verify_signature_init, cms)(CountersignatureImpl* impl) { assert(impl->type == CS_IMPL_CMS); return CMS_dataInit(impl->cms, NULL); } int IMPL_FUNC_NAME(verify_signature_finish, pkcs7)( CountersignatureImpl* impl, BIO* bio, X509* signer) { assert(impl->type == CS_IMPL_PKCS7); /* Verify signature with PKCS7_signatureVerify because TS_RESP_verify_token would try to verify chain and without trust anchors it always fails */ PKCS7_SIGNER_INFO* si = sk_PKCS7_SIGNER_INFO_value(PKCS7_get_signer_info(impl->pkcs7), 0); return PKCS7_signatureVerify(bio, impl->pkcs7, si, signer); } int IMPL_FUNC_NAME(verify_signature_finish, cms)(CountersignatureImpl* impl, BIO* bio, X509* signer) { assert(impl->type == CS_IMPL_CMS); (void)signer; CMS_SignerInfo* si = sk_CMS_SignerInfo_value(CMS_get0_SignerInfos(impl->cms), 0); return CMS_SignerInfo_verify_content(si, bio); } CountersignatureImpl* ms_countersig_impl_new(const uint8_t* data, long size) { const uint8_t* d = data; PKCS7* p7 = d2i_PKCS7(NULL, &d, size); if (p7 && PKCS7_type_is_signed(p7) && p7->d.sign) { CountersignatureImpl* result = (CountersignatureImpl*)calloc(1, sizeof(CountersignatureImpl)); result->type = CS_IMPL_PKCS7; result->funcs = &FUNC_ARRAY_NAME_FOR_IMPL(pkcs7); result->pkcs7 = p7; return result; } else if (p7) { PKCS7_free(p7); return NULL; } d = data; CMS_ContentInfo* cms = d2i_CMS_ContentInfo(NULL, &d, size); if (cms) { CountersignatureImpl* result = (CountersignatureImpl*)calloc(1, sizeof(CountersignatureImpl)); result->type = CS_IMPL_CMS; result->funcs = &FUNC_ARRAY_NAME_FOR_IMPL(cms); result->cms = cms; return result; } return NULL; } void ms_countersig_impl_free(CountersignatureImpl* impl) { switch (impl->type) { case CS_IMPL_PKCS7: PKCS7_free(impl->pkcs7); break; case CS_IMPL_CMS: if (impl->_certs) { sk_X509_pop_free(impl->_certs, X509_free); } CMS_ContentInfo_free(impl->cms); break; } free(impl); } Countersignature* ms_countersig_new(const uint8_t* data, long size, ASN1_STRING* enc_digest) { Countersignature* result = (Countersignature*)calloc(1, sizeof(*result)); if (!result) return NULL; CountersignatureImpl* impl = ms_countersig_impl_new(data, size); if (!impl) { result->verify_flags = COUNTERSIGNATURE_VFY_CANT_PARSE; return result; } TS_TST_INFO* ts = impl->funcs->get_ts_tst_info(impl); if (!ts) { result->verify_flags = COUNTERSIGNATURE_VFY_CANT_PARSE; ms_countersig_impl_free(impl); return result; } const ASN1_TIME* rawTime = TS_TST_INFO_get_time(ts); if (!rawTime) { result->verify_flags = COUNTERSIGNATURE_VFY_TIME_MISSING; TS_TST_INFO_free(ts); ms_countersig_impl_free(impl); return result; } result->sign_time = ASN1_TIME_to_int64_t(rawTime); STACK_OF(X509)* sigs = impl->funcs->get_signers(impl); X509* signCert = sk_X509_value(sigs, 0); if (!signCert) { result->verify_flags = COUNTERSIGNATURE_VFY_NO_SIGNER_CERT; goto end; } STACK_OF(X509)* certs = impl->funcs->get_certs(impl); /* MS Counter signatures (PKCS7/CMS) can have extra certificates that are not part of a chain */ result->certs = certificate_array_new(sk_X509_num(certs)); if (!result->certs) { result->verify_flags = AUTHENTICODE_VFY_INTERNAL_ERROR; goto end; } parse_x509_certificates(certs, result->certs); result->chain = parse_signer_chain(signCert, certs); /* Imprint == digest */ TS_MSG_IMPRINT* imprint = TS_TST_INFO_get_msg_imprint(ts); if (!imprint) { result->verify_flags = COUNTERSIGNATURE_VFY_DIGEST_MISSING; goto end; } X509_ALGOR* digestAlg = TS_MSG_IMPRINT_get_algo(imprint); int digestnid = OBJ_obj2nid(digestAlg->algorithm); result->digest_alg = strdup(OBJ_nid2ln(digestnid)); ASN1_STRING* rawDigest = TS_MSG_IMPRINT_get_msg(imprint); int digestLen = rawDigest->length; uint8_t* digestData = rawDigest->data; byte_array_init(&result->digest, digestData, digestLen); if (!digestLen) { result->verify_flags = COUNTERSIGNATURE_VFY_DIGEST_MISSING; goto end; } const EVP_MD* md = EVP_get_digestbynid(digestnid); if (!md) { result->verify_flags = COUNTERSIGNATURE_VFY_UNKNOWN_ALGORITHM; goto end; } uint8_t calc_digest[EVP_MAX_MD_SIZE]; calculate_digest(md, enc_digest->data, enc_digest->length, calc_digest); #if OPENSSL_VERSION_NUMBER >= 0x3000000fL int mdLen = EVP_MD_get_size(md); #else int mdLen = EVP_MD_size(md); #endif if (digestLen != mdLen || memcmp(calc_digest, digestData, mdLen) != 0) { result->verify_flags = COUNTERSIGNATURE_VFY_DOESNT_MATCH_SIGNATURE; goto end; } bool isValid = impl->funcs->verify_digest(impl, calc_digest, mdLen) == 1; if (!isValid) { result->verify_flags = COUNTERSIGNATURE_VFY_INVALID; goto end; } BIO* bio = impl->funcs->verify_signature_init(impl); char buf[4096]; /* We now have to 'read' from bio to calculate digests etc. */ while (BIO_read(bio, buf, sizeof(buf)) > 0) continue; isValid = impl->funcs->verify_signature_finish(impl, bio, signCert) == 1; BIO_free_all(bio); if (!isValid) result->verify_flags = COUNTERSIGNATURE_VFY_INVALID; end: sk_X509_free(sigs); TS_TST_INFO_free(ts); ms_countersig_impl_free(impl); return result; } int countersignature_array_insert(CountersignatureArray* arr, Countersignature* sig) { Countersignature** tmp = (Countersignature**)realloc(arr->counters, (arr->count + 1) * sizeof(Countersignature*)); if (!tmp) return 1; arr->counters = tmp; arr->counters[arr->count] = sig; arr->count++; return 0; } int countersignature_array_move(CountersignatureArray* dst, CountersignatureArray* src) { size_t newCount = dst->count + src->count; Countersignature** tmp = (Countersignature**)realloc(dst->counters, newCount * sizeof(Countersignature*)); if (!tmp) return 1; dst->counters = tmp; for (size_t i = 0; i < src->count; ++i) dst->counters[i + dst->count] = src->counters[i]; dst->count = newCount; free(src->counters); src->counters = NULL; src->count = 0; return 0; } void countersignature_free(Countersignature* sig) { if (sig) { free(sig->digest_alg); free(sig->digest.data); certificate_array_free(sig->chain); certificate_array_free(sig->certs); free(sig); } } void countersignature_array_free(CountersignatureArray* arr) { if (arr) { for (size_t i = 0; i < arr->count; ++i) { countersignature_free(arr->counters[i]); } free(arr->counters); free(arr); } } yara-4.5.3/libyara/modules/pe/authenticode-parser/countersignature.h000066400000000000000000000037251501365277300257160ustar00rootroot00000000000000/* Copyright (c) 2021 Avast Software 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 AUTHENTICODE_PARSER_COUNTERSIGNATURE_H #define AUTHENTICODE_PARSER_COUNTERSIGNATURE_H #include "certificate.h" #include "helper.h" #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif Countersignature* pkcs9_countersig_new( const uint8_t* data, long size, STACK_OF(X509) * certs, ASN1_STRING* enc_digest); Countersignature* ms_countersig_new(const uint8_t* data, long size, ASN1_STRING* enc_digest); int countersignature_array_insert(CountersignatureArray* arr, Countersignature* sig); /* Moves all countersignatures of src and inserts them into dst */ int countersignature_array_move(CountersignatureArray* dst, CountersignatureArray* src); void countersignature_free(Countersignature* sig); void countersignature_array_free(CountersignatureArray* arr); #ifdef __cplusplus } #endif #endif yara-4.5.3/libyara/modules/pe/authenticode-parser/helper.c000066400000000000000000000044571501365277300235720ustar00rootroot00000000000000/* Copyright (c) 2021 Avast Software 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 "helper.h" #include #include #include #include #include #include uint16_t bswap16(uint16_t d) { return (d << 8) | (d >> 8); } uint32_t bswap32(uint32_t d) { return (((d)&0xff000000) >> 24) | (((d)&0x00ff0000) >> 8) | (((d)&0x0000ff00) << 8) | (((d)&0x000000ff) << 24); } int calculate_digest(const EVP_MD* md, const uint8_t* data, size_t len, uint8_t* digest) { unsigned int outLen = 0; EVP_MD_CTX* mdCtx = EVP_MD_CTX_new(); if (!mdCtx) goto end; if (!EVP_DigestInit_ex(mdCtx, md, NULL) || !EVP_DigestUpdate(mdCtx, data, len) || !EVP_DigestFinal_ex(mdCtx, digest, &outLen)) goto end; end: EVP_MD_CTX_free(mdCtx); return (int)outLen; } int byte_array_init(ByteArray* arr, const uint8_t* data, int len) { if (len == 0) { arr->data = NULL; arr->len = 0; return 0; } arr->data = (uint8_t*)malloc(len); if (!arr->data) return -1; arr->len = len; memcpy(arr->data, data, len); return 0; } int64_t ASN1_TIME_to_int64_t(const ASN1_TIME* time) { struct tm t = {0}; if (!time) return timegm(&t); ASN1_TIME_to_tm(time, &t); return timegm(&t); } yara-4.5.3/libyara/modules/pe/authenticode-parser/helper.h000066400000000000000000000042641501365277300235730ustar00rootroot00000000000000/* Copyright (c) 2021 Avast Software 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 AUTHENTICODE_PARSER_HELPER_H #define AUTHENTICODE_PARSER_HELPER_H #include #include #include #include #include #ifdef _WIN32 #define timegm _mkgmtime #endif #ifdef __cplusplus extern "C" { #endif /* Endianity related functions for PE reading */ uint16_t bswap16(uint16_t d); uint32_t bswap32(uint32_t d); #if defined(WORDS_BIGENDIAN) #define letoh16(x) bswap16(x) #define letoh32(x) bswap32(x) #define betoh16(x) (x) #define betoh32(x) (x) #else #define letoh16(x) (x) #define letoh32(x) (x) #define betoh16(x) bswap16(x) #define betoh32(x) bswap32(x) #endif /* Calculates digest md of data, return bytes written to digest or 0 on error * Maximum of EVP_MAX_MD_SIZE will be written to digest */ int calculate_digest(const EVP_MD* md, const uint8_t* data, size_t len, uint8_t* digest); /* Copies data of length len into already existing arr */ int byte_array_init(ByteArray* arr, const uint8_t* data, int len); /* Converts ASN1_TIME string time into a unix timestamp */ int64_t ASN1_TIME_to_int64_t(const ASN1_TIME* time); #ifdef __cplusplus } #endif #endif yara-4.5.3/libyara/modules/pe/authenticode-parser/structs.c000066400000000000000000000063031501365277300240120ustar00rootroot00000000000000/* Copyright (c) 2021 Avast Software 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 "structs.h" ASN1_CHOICE(SpcString) = { ASN1_IMP_OPT(SpcString, value.unicode, ASN1_BMPSTRING, 0), ASN1_IMP_OPT(SpcString, value.ascii, ASN1_IA5STRING, 1) } ASN1_CHOICE_END(SpcString) ASN1_SEQUENCE(SpcSerializedObject) = { ASN1_SIMPLE(SpcSerializedObject, classId, ASN1_OCTET_STRING), ASN1_SIMPLE(SpcSerializedObject, serializedData, ASN1_OCTET_STRING) } ASN1_SEQUENCE_END(SpcSerializedObject) ASN1_CHOICE(SpcLink) = { ASN1_IMP_OPT(SpcLink, value.url, ASN1_IA5STRING, 0), ASN1_IMP_OPT(SpcLink, value.moniker, SpcSerializedObject, 1), ASN1_EXP_OPT(SpcLink, value.file, SpcString, 2) } ASN1_CHOICE_END(SpcLink) ASN1_SEQUENCE(SpcAttributeTypeAndOptionalValue) = { ASN1_SIMPLE(SpcAttributeTypeAndOptionalValue, type, ASN1_OBJECT), ASN1_OPT(SpcAttributeTypeAndOptionalValue, value, ASN1_ANY) } ASN1_SEQUENCE_END(SpcAttributeTypeAndOptionalValue) ASN1_SEQUENCE(SpcPeImageData) = { ASN1_SIMPLE(SpcPeImageData, flags, ASN1_BIT_STRING), ASN1_EXP_OPT(SpcPeImageData, file, SpcLink, 0) } ASN1_SEQUENCE_END(SpcPeImageData) ASN1_SEQUENCE(AlgorithmIdentifier) = { ASN1_SIMPLE(AlgorithmIdentifier, algorithm, ASN1_OBJECT), ASN1_OPT(AlgorithmIdentifier, parameters, ASN1_ANY) } ASN1_SEQUENCE_END(AlgorithmIdentifier) ASN1_SEQUENCE(DigestInfo) = { ASN1_SIMPLE(DigestInfo, digestAlgorithm, AlgorithmIdentifier), ASN1_SIMPLE(DigestInfo, digest, ASN1_OCTET_STRING) } ASN1_SEQUENCE_END(DigestInfo) ASN1_SEQUENCE(SpcIndirectDataContent) = { ASN1_SIMPLE(SpcIndirectDataContent, data, SpcAttributeTypeAndOptionalValue), ASN1_SIMPLE(SpcIndirectDataContent, messageDigest, DigestInfo) } ASN1_SEQUENCE_END(SpcIndirectDataContent) ASN1_SEQUENCE(SpcSpOpusInfo) = { ASN1_EXP_OPT(SpcSpOpusInfo, programName, SpcString, 0), ASN1_EXP_OPT(SpcSpOpusInfo, moreInfo, SpcLink, 1) } ASN1_SEQUENCE_END(SpcSpOpusInfo) IMPLEMENT_ASN1_FUNCTIONS(SpcString) IMPLEMENT_ASN1_FUNCTIONS(SpcSerializedObject) IMPLEMENT_ASN1_FUNCTIONS(SpcLink) IMPLEMENT_ASN1_FUNCTIONS(SpcAttributeTypeAndOptionalValue) IMPLEMENT_ASN1_FUNCTIONS(SpcPeImageData) IMPLEMENT_ASN1_FUNCTIONS(AlgorithmIdentifier) IMPLEMENT_ASN1_FUNCTIONS(DigestInfo) IMPLEMENT_ASN1_FUNCTIONS(SpcIndirectDataContent) IMPLEMENT_ASN1_FUNCTIONS(SpcSpOpusInfo) yara-4.5.3/libyara/modules/pe/authenticode-parser/structs.h000066400000000000000000000060071501365277300240200ustar00rootroot00000000000000/* Copyright (c) 2021 Avast Software 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 AUTHENTICODE_PARSER_STRUCTS_H #define AUTHENTICODE_PARSER_STRUCTS_H #include #include #include #include #ifdef __cplusplus extern "C" { #endif #define NID_spc_info "1.3.6.1.4.1.311.2.1.12" #define NID_spc_ms_countersignature "1.3.6.1.4.1.311.3.3.1" #define NID_spc_nested_signature "1.3.6.1.4.1.311.2.4.1" #define NID_spc_indirect_data "1.3.6.1.4.1.311.2.1.4" typedef struct { int type; union { ASN1_BMPSTRING *unicode; ASN1_IA5STRING *ascii; } value; } SpcString; typedef struct { ASN1_OCTET_STRING *classId; ASN1_OCTET_STRING *serializedData; } SpcSerializedObject; typedef struct { int type; union { ASN1_IA5STRING *url; SpcSerializedObject *moniker; SpcString *file; } value; } SpcLink; typedef struct { ASN1_OBJECT *type; ASN1_TYPE *value; } SpcAttributeTypeAndOptionalValue; typedef struct { ASN1_BIT_STRING *flags; SpcLink *file; } SpcPeImageData; typedef struct { ASN1_OBJECT *algorithm; ASN1_TYPE *parameters; } AlgorithmIdentifier; typedef struct { AlgorithmIdentifier *digestAlgorithm; ASN1_OCTET_STRING *digest; } DigestInfo; typedef struct { SpcAttributeTypeAndOptionalValue *data; DigestInfo *messageDigest; } SpcIndirectDataContent; typedef struct { ASN1_OBJECT *contentType; SpcIndirectDataContent *content; } SpcContentInfo; typedef struct { SpcString *programName; SpcLink *moreInfo; } SpcSpOpusInfo; DECLARE_ASN1_FUNCTIONS(SpcString) DECLARE_ASN1_FUNCTIONS(SpcSerializedObject) DECLARE_ASN1_FUNCTIONS(SpcLink) DECLARE_ASN1_FUNCTIONS(SpcAttributeTypeAndOptionalValue) DECLARE_ASN1_FUNCTIONS(SpcPeImageData) DECLARE_ASN1_FUNCTIONS(AlgorithmIdentifier) DECLARE_ASN1_FUNCTIONS(DigestInfo) DECLARE_ASN1_FUNCTIONS(SpcIndirectDataContent) DECLARE_ASN1_FUNCTIONS(SpcSpOpusInfo) DECLARE_ASN1_FUNCTIONS(SpcContentInfo) #ifdef __cplusplus } #endif #endif yara-4.5.3/libyara/modules/pe/pe.c000066400000000000000000004030261501365277300167440ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "../crypto.h" #if defined(HAVE_LIBCRYPTO) #include #include #endif #include #include #include #include #include #include #include #include #include #define MODULE_NAME pe #define IMPORT_STANDARD 1 #define IMPORT_DELAYED 2 #define IMPORT_ANY (~0) // http://msdn.microsoft.com/en-us/library/ms648009(v=vs.85).aspx #define RESOURCE_TYPE_CURSOR 1 #define RESOURCE_TYPE_BITMAP 2 #define RESOURCE_TYPE_ICON 3 #define RESOURCE_TYPE_MENU 4 #define RESOURCE_TYPE_DIALOG 5 #define RESOURCE_TYPE_STRING 6 #define RESOURCE_TYPE_FONTDIR 7 #define RESOURCE_TYPE_FONT 8 #define RESOURCE_TYPE_ACCELERATOR 9 #define RESOURCE_TYPE_RCDATA 10 #define RESOURCE_TYPE_MESSAGETABLE 11 #define RESOURCE_TYPE_GROUP_CURSOR \ 12 // MAKEINTRESOURCE((ULONG_PTR)(RT_CURSOR) + 11) #define RESOURCE_TYPE_GROUP_ICON \ 14 // MAKEINTRESOURCE((ULONG_PTR)(RT_ICON) + 11) #define RESOURCE_TYPE_VERSION 16 #define RESOURCE_TYPE_DLGINCLUDE 17 #define RESOURCE_TYPE_PLUGPLAY 19 #define RESOURCE_TYPE_VXD 20 #define RESOURCE_TYPE_ANICURSOR 21 #define RESOURCE_TYPE_ANIICON 22 #define RESOURCE_TYPE_HTML 23 #define RESOURCE_TYPE_MANIFEST 24 #define RESOURCE_CALLBACK_CONTINUE 0 #define RESOURCE_CALLBACK_ABORT 1 #define RESOURCE_ITERATOR_FINISHED 0 #define RESOURCE_ITERATOR_ABORTED 1 #define MAX_PE_IMPORTS 16384 #define MAX_PE_EXPORTS 16384 #define MAX_EXPORT_NAME_LENGTH 512 #define MAX_IMPORT_DLL_NAME_LENGTH 256 #define MAX_RESOURCES 65536 #define IS_RESOURCE_SUBDIRECTORY(entry) \ (yr_le32toh((entry)->OffsetToData) & 0x80000000) #define RESOURCE_OFFSET(entry) (yr_le32toh((entry)->OffsetToData) & 0x7FFFFFFF) typedef int (*RESOURCE_CALLBACK_FUNC)( PIMAGE_RESOURCE_DATA_ENTRY rsrc_data, int rsrc_type, int rsrc_id, int rsrc_language, const IMAGE_RESOURCE_DIR_STRING_U* type_string, const IMAGE_RESOURCE_DIR_STRING_U* name_string, const IMAGE_RESOURCE_DIR_STRING_U* lang_string, void* cb_data); static size_t available_space(PE* pe, void* pointer) { if ((uint8_t*) pointer < pe->data) return 0; if ((uint8_t*) pointer >= pe->data + pe->data_size) return 0; return pe->data + pe->data_size - (uint8_t*) pointer; } static int wide_string_fits_in_pe(PE* pe, char* data) { size_t i = 0; size_t space_left = available_space(pe, data); while (space_left >= 2) { if (data[i] == 0 && data[i + 1] == 0) return 1; space_left -= 2; i += 2; } return 0; } // Parse the rich signature. // http://www.ntcore.com/files/richsign.htm static void pe_parse_rich_signature(PE* pe, uint64_t base_address) { PIMAGE_DOS_HEADER mz_header; PRICH_SIGNATURE rich_signature = NULL; DWORD* rich_ptr = NULL; BYTE* raw_data = NULL; BYTE* clear_data = NULL; BYTE* version_data = NULL; DWORD* p = NULL; uint32_t nthdr_offset = 0; uint32_t key = 0; size_t rich_len = 0; int64_t rich_count = 0; if (pe->data_size < sizeof(IMAGE_DOS_HEADER)) return; mz_header = (PIMAGE_DOS_HEADER) pe->data; if (yr_le16toh(mz_header->e_magic) != IMAGE_DOS_SIGNATURE) return; // To find the Rich marker we start at the NT header and work backwards, so // make sure we have at least enough data to get to the NT header. nthdr_offset = yr_le32toh(mz_header->e_lfanew); if (nthdr_offset > pe->data_size + sizeof(uint32_t) || nthdr_offset < 4) return; // Most files have the Rich header at offset 0x80, but that is not always // true. 582ce3eea9c97d5e89f7d83953a6d518b16770e635a19a456c0225449c6967a4 is // one sample which has a Rich header starting at offset 0x200. To properly // find the Rich header we need to start at the NT header and work backwards. p = (DWORD*) (pe->data + nthdr_offset - 4); while (p >= (DWORD*) (pe->data + sizeof(IMAGE_DOS_HEADER))) { if (yr_le32toh(*p) == RICH_RICH) { // The XOR key is the dword following the Rich value. We use this to find // DanS header only. key = *(p + 1); rich_ptr = p; --p; break; } // The NT header is 8 byte aligned so we can move back in 4 byte increments. --p; } // If we haven't found a key we can skip processing the rest. if (key == 0) return; // If we have found the key we need to now find the start (DanS). while (p >= (DWORD*) (pe->data + sizeof(IMAGE_DOS_HEADER))) { if (yr_le32toh((*(p) ^ key)) == RICH_DANS) { rich_signature = (PRICH_SIGNATURE) p; break; } --p; } if (rich_signature == NULL) return; // Multiply by 4 because we are counting in DWORDs. rich_len = (rich_ptr - (DWORD*) rich_signature) * 4; raw_data = (BYTE*) yr_malloc(rich_len); if (!raw_data) return; memcpy(raw_data, rich_signature, rich_len); yr_set_integer( base_address + ((uint8_t*) rich_signature - pe->data), pe->object, "rich_signature.offset"); yr_set_integer(rich_len, pe->object, "rich_signature.length"); yr_set_integer(yr_le32toh(key), pe->object, "rich_signature.key"); clear_data = (BYTE*) yr_malloc(rich_len); if (!clear_data) { yr_free(raw_data); return; } // Copy the entire block here to be XORed. memcpy(clear_data, raw_data, rich_len); for (rich_ptr = (DWORD*) clear_data; rich_ptr < (DWORD*) (clear_data + rich_len); rich_ptr++) { *rich_ptr ^= key; } yr_set_sized_string( (char*) raw_data, rich_len, pe->object, "rich_signature.raw_data"); yr_free(raw_data); yr_set_sized_string( (char*) clear_data, rich_len, pe->object, "rich_signature.clear_data"); // Allocate space for just the version data. This is a series of every other // dword from the clear data. This is useful to be able to hash alone. // We need to skip the first 3 DWORDs of the RICH_SIGNATURE, which are DanS // and XOR keys. rich_count = (rich_len - sizeof(RICH_SIGNATURE)) / sizeof(RICH_VERSION_INFO); version_data = (BYTE*) yr_malloc(rich_count * sizeof(DWORD)); if (!version_data) { yr_free(clear_data); return; } rich_signature = (PRICH_SIGNATURE) clear_data; for (int i = 0; i < rich_count; i++) { memcpy( version_data + (i * sizeof(DWORD)), &rich_signature->versions[i], sizeof(DWORD)); } yr_set_sized_string( (char*) version_data, rich_count * sizeof(DWORD), pe->object, "rich_signature.version_data"); yr_free(clear_data); yr_free(version_data); } static void pe_parse_debug_directory(PE* pe) { PIMAGE_DATA_DIRECTORY data_dir; PIMAGE_DEBUG_DIRECTORY debug_dir; int64_t debug_dir_offset; int i, dcount; size_t pdb_path_len; char* pdb_path = NULL; data_dir = pe_get_directory_entry(pe, IMAGE_DIRECTORY_ENTRY_DEBUG); if (data_dir == NULL) return; if (yr_le32toh(data_dir->Size) == 0) return; if (yr_le32toh(data_dir->VirtualAddress) == 0) return; debug_dir_offset = pe_rva_to_offset(pe, yr_le32toh(data_dir->VirtualAddress)); if (debug_dir_offset < 0) return; dcount = yr_le32toh(data_dir->Size) / sizeof(IMAGE_DEBUG_DIRECTORY); for (i = 0; i < dcount; i++) { int64_t pcv_hdr_offset = 0; debug_dir = (PIMAGE_DEBUG_DIRECTORY) (pe->data + debug_dir_offset + i * sizeof(IMAGE_DEBUG_DIRECTORY)); if (!struct_fits_in_pe(pe, debug_dir, IMAGE_DEBUG_DIRECTORY)) break; if (yr_le32toh(debug_dir->Type) != IMAGE_DEBUG_TYPE_CODEVIEW) continue; // The debug info offset may be present either as RVA or as raw offset // Sample: 0249e00b6d46bee5a17096559f18e671cd0ceee36373e8708f614a9a6c7c079e if (debug_dir->AddressOfRawData != 0) { pcv_hdr_offset = pe_rva_to_offset( pe, yr_le32toh(debug_dir->AddressOfRawData)); } // Give it chance to read it from the RAW offset // Sample: 735f72b3fcd72789f01e923c9de2a9ab5b5ffbece23633da81d976ad0ad159e3 if (pcv_hdr_offset <= 0 && debug_dir->PointerToRawData != 0) { pcv_hdr_offset = yr_le32toh(debug_dir->PointerToRawData); } if (pcv_hdr_offset <= 0) continue; PCV_HEADER cv_hdr = (PCV_HEADER) (pe->data + pcv_hdr_offset); if (!struct_fits_in_pe(pe, cv_hdr, CV_HEADER)) continue; if (yr_le32toh(cv_hdr->dwSignature) == CVINFO_PDB20_CVSIGNATURE) { PCV_INFO_PDB20 pdb20 = (PCV_INFO_PDB20) cv_hdr; if (struct_fits_in_pe(pe, pdb20, CV_INFO_PDB20)) pdb_path = (char*) (pdb20->PdbFileName); } else if (yr_le32toh(cv_hdr->dwSignature) == CVINFO_PDB70_CVSIGNATURE) { PCV_INFO_PDB70 pdb70 = (PCV_INFO_PDB70) cv_hdr; if (struct_fits_in_pe(pe, pdb70, CV_INFO_PDB70)) pdb_path = (char*) (pdb70->PdbFileName); } else if (yr_le32toh(cv_hdr->dwSignature) == CODEVIEW_SIGNATURE_MTOC) { PMTOC_ENTRY mtoc = (PMTOC_ENTRY) cv_hdr; if (struct_fits_in_pe(pe, mtoc, MTOC_ENTRY)) pdb_path = (char*) (mtoc->PdbFileName); } if (pdb_path != NULL) { pdb_path_len = strnlen( pdb_path, yr_min(available_space(pe, pdb_path), YR_MAX_PATH)); if (pdb_path_len >= 0 && pdb_path_len < YR_MAX_PATH) { yr_set_sized_string(pdb_path, pdb_path_len, pe->object, "pdb_path"); break; } } } } // Return a pointer to the resource directory string or NULL. // The callback function will parse this and call yr_set_sized_string(). // The pointer is guaranteed to have enough space to contain the entire string. static const PIMAGE_RESOURCE_DIR_STRING_U parse_resource_name( PE* pe, const uint8_t* rsrc_data, PIMAGE_RESOURCE_DIRECTORY_ENTRY entry) { // If high bit is set it is an offset relative to rsrc_data, which contains // a resource directory string. if (yr_le32toh(entry->Name) & 0x80000000) { const PIMAGE_RESOURCE_DIR_STRING_U pNameString = (PIMAGE_RESOURCE_DIR_STRING_U) (rsrc_data + (yr_le32toh(entry->Name) & 0x7FFFFFFF)); // A resource directory string is 2 bytes for the length and then a variable // length Unicode string. Make sure we have at least 2 bytes. if (!fits_in_pe(pe, pNameString, 2)) return NULL; // Sanity check for strings that are excesively large. if (pNameString->Length > 1000) return NULL; // Move past the length and make sure we have enough bytes for the string. if (!fits_in_pe( pe, pNameString, sizeof(uint16_t) + yr_le16toh(pNameString->Length) * 2)) return NULL; return pNameString; } return NULL; } static int _pe_iterate_resources( PE* pe, PIMAGE_RESOURCE_DIRECTORY resource_dir, const uint8_t* rsrc_data, int rsrc_tree_level, int* type, int* id, int* language, const IMAGE_RESOURCE_DIR_STRING_U* type_string, const IMAGE_RESOURCE_DIR_STRING_U* name_string, const IMAGE_RESOURCE_DIR_STRING_U* lang_string, RESOURCE_CALLBACK_FUNC callback, void* callback_data) { int i, result = RESOURCE_ITERATOR_FINISHED; int total_entries; PIMAGE_RESOURCE_DIRECTORY_ENTRY entry; // A few sanity checks to avoid corrupt files if (yr_le32toh(resource_dir->Characteristics) != 0 || yr_le16toh(resource_dir->NumberOfNamedEntries) > 32768 || yr_le16toh(resource_dir->NumberOfIdEntries) > 32768) { return result; } total_entries = yr_le16toh(resource_dir->NumberOfNamedEntries) + yr_le16toh(resource_dir->NumberOfIdEntries); // The first directory entry is just after the resource directory, // by incrementing resource_dir we skip sizeof(resource_dir) bytes // and get a pointer to the end of the resource directory. entry = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (resource_dir + 1); if (!fits_in_pe( pe, entry, total_entries * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY))) return result; for (i = 0; i < total_entries; i++) { if (yr_le32toh(entry->OffsetToData) == 0) continue; switch (rsrc_tree_level) { case 0: *type = yr_le32toh(entry->Name); type_string = parse_resource_name(pe, rsrc_data, entry); break; case 1: *id = yr_le32toh(entry->Name); name_string = parse_resource_name(pe, rsrc_data, entry); break; case 2: *language = yr_le32toh(entry->Name); lang_string = parse_resource_name(pe, rsrc_data, entry); break; } if (IS_RESOURCE_SUBDIRECTORY(entry) && rsrc_tree_level < 2) { PIMAGE_RESOURCE_DIRECTORY directory = (PIMAGE_RESOURCE_DIRECTORY) (rsrc_data + RESOURCE_OFFSET(entry)); if (struct_fits_in_pe(pe, directory, IMAGE_RESOURCE_DIRECTORY)) { result = _pe_iterate_resources( pe, directory, rsrc_data, rsrc_tree_level + 1, type, id, language, type_string, name_string, lang_string, callback, callback_data); } } else { PIMAGE_RESOURCE_DATA_ENTRY data_entry = (PIMAGE_RESOURCE_DATA_ENTRY) (rsrc_data + RESOURCE_OFFSET(entry)); if (struct_fits_in_pe(pe, data_entry, IMAGE_RESOURCE_DATA_ENTRY)) { if (yr_le32toh(data_entry->Size) > 0 && // We could use the PE's size as an upper bound for the entry size, // but there are some truncated files where the PE size is lower. // Use a reasonably large value as the upper bound and avoid some // completely corrupt entries with random values. yr_le32toh(data_entry->Size) <= 0x3FFFFFFF) { if (callback( data_entry, *type, *id, *language, type_string, name_string, lang_string, callback_data) == RESOURCE_CALLBACK_ABORT) { result = RESOURCE_ITERATOR_ABORTED; } } } } if (result == RESOURCE_ITERATOR_ABORTED) break; entry++; } return result; } static int pe_iterate_resources( PE* pe, RESOURCE_CALLBACK_FUNC callback, void* callback_data) { int64_t offset; int type = -1; int id = -1; int language = -1; IMAGE_RESOURCE_DIR_STRING_U* type_string = NULL; IMAGE_RESOURCE_DIR_STRING_U* name_string = NULL; IMAGE_RESOURCE_DIR_STRING_U* lang_string = NULL; PIMAGE_DATA_DIRECTORY directory = pe_get_directory_entry( pe, IMAGE_DIRECTORY_ENTRY_RESOURCE); if (directory == NULL) return 0; if (yr_le32toh(directory->VirtualAddress) != 0) { PIMAGE_RESOURCE_DIRECTORY rsrc_dir; offset = pe_rva_to_offset(pe, yr_le32toh(directory->VirtualAddress)); if (offset < 0) return 0; rsrc_dir = (PIMAGE_RESOURCE_DIRECTORY) (pe->data + offset); if (struct_fits_in_pe(pe, rsrc_dir, IMAGE_RESOURCE_DIRECTORY)) { yr_set_integer( yr_le32toh(rsrc_dir->TimeDateStamp), pe->object, "resource_timestamp"); yr_set_integer( yr_le16toh(rsrc_dir->MajorVersion), pe->object, "resource_version.major"); yr_set_integer( yr_le16toh(rsrc_dir->MinorVersion), pe->object, "resource_version.minor"); _pe_iterate_resources( pe, rsrc_dir, pe->data + offset, 0, &type, &id, &language, type_string, name_string, lang_string, callback, callback_data); return 1; } } return 0; } // Align offset to a 32-bit boundary and add it to a pointer #define ADD_OFFSET(ptr, offset) \ (PVERSION_INFO)((uint8_t*) (ptr) + ((offset + 3) & ~3)) static void pe_parse_version_info(PIMAGE_RESOURCE_DATA_ENTRY rsrc_data, PE* pe) { PVERSION_INFO version_info; int64_t version_info_offset = pe_rva_to_offset( pe, yr_le32toh(rsrc_data->OffsetToData)); if (version_info_offset < 0) return; version_info = (PVERSION_INFO) (pe->data + version_info_offset); if (!struct_fits_in_pe(pe, version_info, VERSION_INFO)) return; if (!fits_in_pe(pe, version_info->Key, sizeof("VS_VERSION_INFO") * 2)) return; if (strcmp_w(version_info->Key, "VS_VERSION_INFO") != 0) return; version_info = ADD_OFFSET(version_info, sizeof(VERSION_INFO) + 86); while (fits_in_pe(pe, version_info->Key, sizeof("VarFileInfo") * 2) && strcmp_w(version_info->Key, "VarFileInfo") == 0 && yr_le16toh(version_info->Length) != 0) { version_info = ADD_OFFSET(version_info, yr_le16toh(version_info->Length)); } while (fits_in_pe(pe, version_info->Key, sizeof("StringFileInfo") * 2) && strcmp_w(version_info->Key, "StringFileInfo") == 0 && yr_le16toh(version_info->Length) != 0) { PVERSION_INFO string_table = ADD_OFFSET( version_info, sizeof(VERSION_INFO) + 30); version_info = ADD_OFFSET(version_info, yr_le16toh(version_info->Length)); while (struct_fits_in_pe(pe, string_table, VERSION_INFO) && wide_string_fits_in_pe(pe, string_table->Key) && yr_le16toh(string_table->Length) != 0 && string_table < version_info) { PVERSION_INFO string = ADD_OFFSET( string_table, sizeof(VERSION_INFO) + 2 * (strnlen_w(string_table->Key) + 1)); string_table = ADD_OFFSET(string_table, yr_le16toh(string_table->Length)); while (struct_fits_in_pe(pe, string, VERSION_INFO) && wide_string_fits_in_pe(pe, string->Key) && yr_le16toh(string->Length) != 0 && string < string_table) { char* string_value = (char*) ADD_OFFSET( string, sizeof(VERSION_INFO) + 2 * (strnlen_w(string->Key) + 1)); if (wide_string_fits_in_pe(pe, string_value)) { char key[64]; char value[256]; strlcpy_w(key, string->Key, sizeof(key)); strlcpy_w(value, string_value, sizeof(value)); // null terminator of string is not included in version value when // ValueLength is zero if (yr_le16toh(string->ValueLength) == 0) value[yr_le16toh(string->ValueLength)] = '\0'; yr_set_string(value, pe->object, "version_info[%s]", key); yr_set_string( key, pe->object, "version_info_list[%i].key", pe->version_infos); yr_set_string( value, pe->object, "version_info_list[%i].value", pe->version_infos); pe->version_infos += 1; } string = ADD_OFFSET(string, yr_le16toh(string->Length)); } } } } static void pe_set_resource_string_or_id( IMAGE_RESOURCE_DIR_STRING_U* rsrc_string, int rsrc_int, const char* string_description, const char* int_description, PE* pe) { if (rsrc_string) { // Multiply by 2 because it is a Unicode string. size_t length = yr_le16toh(rsrc_string->Length) * 2; // Check if the whole string fits in the PE image. // If not, the name becomes UNDEFINED by default. if (fits_in_pe(pe, rsrc_string->NameString, length)) { yr_set_sized_string( (char*) rsrc_string->NameString, length, pe->object, string_description, pe->resources); } } else { if (rsrc_int != -1) yr_set_integer(rsrc_int, pe->object, int_description, pe->resources); } } static int pe_collect_resources( PIMAGE_RESOURCE_DATA_ENTRY rsrc_data, int rsrc_type, int rsrc_id, int rsrc_language, IMAGE_RESOURCE_DIR_STRING_U* type_string, IMAGE_RESOURCE_DIR_STRING_U* name_string, IMAGE_RESOURCE_DIR_STRING_U* lang_string, PE* pe) { // Don't collect too many resources. if (pe->resources >= MAX_RESOURCES) return RESOURCE_CALLBACK_CONTINUE; yr_set_integer( yr_le32toh(rsrc_data->OffsetToData), pe->object, "resources[%i].rva", pe->resources); int64_t offset = pe_rva_to_offset(pe, yr_le32toh(rsrc_data->OffsetToData)); if (offset < 0) offset = YR_UNDEFINED; yr_set_integer(offset, pe->object, "resources[%i].offset", pe->resources); yr_set_integer( yr_le32toh(rsrc_data->Size), pe->object, "resources[%i].length", pe->resources); pe_set_resource_string_or_id( type_string, rsrc_type, "resources[%i].type_string", "resources[%i].type", pe); pe_set_resource_string_or_id( name_string, rsrc_id, "resources[%i].name_string", "resources[%i].id", pe); pe_set_resource_string_or_id( lang_string, rsrc_language, "resources[%i].language_string", "resources[%i].language", pe); // Resources we do extra parsing on if (rsrc_type == RESOURCE_TYPE_VERSION) pe_parse_version_info(rsrc_data, pe); pe->resources += 1; return RESOURCE_CALLBACK_CONTINUE; } // Function names should have only lowercase, uppercase, digits and a small // subset of special characters. This is to match behavior of pefile. See // https://github.com/erocarrera/pefile/blob/593d094e35198dad92aaf040bef17eb800c8a373/pefile.py#L2326-L2348 static int valid_function_name(char* name) { if (!strcmp(name, "")) return 0; size_t i = 0; for (char c = name[i]; c != '\x00'; c = name[++i]) { if (!(c >= 'a' && c <= 'z') && !(c >= 'A' && c <= 'Z') && !(c >= '0' && c <= '9') && c != '.' && c != '_' && c != '?' && c != '@' && c != '$' && c != '(' && c != ')' && c != '<' && c != '>') return 0; } return 1; } static IMPORT_FUNCTION* pe_parse_import_descriptor( PE* pe, PIMAGE_IMPORT_DESCRIPTOR import_descriptor, char* dll_name, int* num_function_imports) { IMPORT_FUNCTION* head = NULL; IMPORT_FUNCTION* tail = NULL; // This is tracked separately from num_function_imports because that is the // number of successfully parsed imports, while this is the number of imports // attempted to be parsed. This allows us to stop parsing on too many imports // while still accurately recording the number of successfully parsed imports. int parsed_imports = 0; int64_t offset = pe_rva_to_offset( pe, yr_le32toh(import_descriptor->OriginalFirstThunk)); // I've seen binaries where OriginalFirstThunk is zero. In this case // use FirstThunk. if (offset <= 0) offset = pe_rva_to_offset(pe, yr_le32toh(import_descriptor->FirstThunk)); if (offset < 0) return NULL; if (IS_64BITS_PE(pe)) { PIMAGE_THUNK_DATA64 thunks64 = (PIMAGE_THUNK_DATA64) (pe->data + offset); uint64_t func_idx = 0; while (struct_fits_in_pe(pe, thunks64, IMAGE_THUNK_DATA64) && yr_le64toh(thunks64->u1.Ordinal) != 0 && parsed_imports < MAX_PE_IMPORTS && *num_function_imports < MAX_PE_IMPORTS) { char* name = NULL; uint16_t ordinal = 0; uint8_t has_ordinal = 0; uint64_t rva_address = 0; parsed_imports++; if (!(yr_le64toh(thunks64->u1.Ordinal) & IMAGE_ORDINAL_FLAG64)) { // If imported by name offset = pe_rva_to_offset(pe, yr_le64toh(thunks64->u1.Function)); if (offset >= 0) { PIMAGE_IMPORT_BY_NAME import = (PIMAGE_IMPORT_BY_NAME) (pe->data + offset); if (struct_fits_in_pe(pe, import, IMAGE_IMPORT_BY_NAME)) { name = (char*) yr_strndup( (char*) import->Name, yr_min(available_space(pe, import->Name), 512)); } } } else { // The maximum possible value for the ordinal is when the high // bit is set (indicating import by ordinal) and the low bits // are FFFF. The maximum number of ordinal exports is 65536. if (yr_le64toh(thunks64->u1.Ordinal) <= 0x800000000000ffff) { ordinal = yr_le64toh(thunks64->u1.Ordinal) & 0xFFFF; name = ord_lookup(dll_name, ordinal); has_ordinal = 1; } } rva_address = yr_le32toh(import_descriptor->FirstThunk) + (sizeof(uint64_t) * func_idx); if (name != NULL && !valid_function_name(name)) { yr_free(name); thunks64++; func_idx++; continue; } if (name != NULL || has_ordinal == 1) { IMPORT_FUNCTION* imported_func = (IMPORT_FUNCTION*) yr_calloc( 1, sizeof(IMPORT_FUNCTION)); if (imported_func == NULL) { yr_free(name); } else { imported_func->name = name; imported_func->ordinal = ordinal; imported_func->has_ordinal = has_ordinal; imported_func->rva = rva_address; imported_func->next = NULL; if (head == NULL) head = imported_func; if (tail != NULL) tail->next = imported_func; tail = imported_func; (*num_function_imports)++; } } thunks64++; func_idx++; } } else { PIMAGE_THUNK_DATA32 thunks32 = (PIMAGE_THUNK_DATA32) (pe->data + offset); uint32_t func_idx = 0; while (struct_fits_in_pe(pe, thunks32, IMAGE_THUNK_DATA32) && yr_le32toh(thunks32->u1.Ordinal) != 0 && parsed_imports < MAX_PE_IMPORTS && *num_function_imports < MAX_PE_IMPORTS) { char* name = NULL; uint16_t ordinal = 0; uint8_t has_ordinal = 0; uint32_t rva_address = 0; parsed_imports++; if (!(yr_le32toh(thunks32->u1.Ordinal) & IMAGE_ORDINAL_FLAG32)) { // If imported by name offset = pe_rva_to_offset(pe, yr_le32toh(thunks32->u1.Function)); if (offset >= 0) { PIMAGE_IMPORT_BY_NAME import = (PIMAGE_IMPORT_BY_NAME) (pe->data + offset); if (struct_fits_in_pe(pe, import, IMAGE_IMPORT_BY_NAME)) { name = (char*) yr_strndup( (char*) import->Name, yr_min(available_space(pe, import->Name), 512)); } } } else { // The maximum possible value for the ordinal is when the high // bit is set (indicating import by ordinal) and the low bits // are FFFF. The maximum number of ordinal exports is 65536. if (yr_le32toh(thunks32->u1.Ordinal) <= 0x8000ffff) { ordinal = yr_le32toh(thunks32->u1.Ordinal) & 0xFFFF; name = ord_lookup(dll_name, ordinal); has_ordinal = 1; } } rva_address = yr_le32toh(import_descriptor->FirstThunk) + (sizeof(uint32_t) * func_idx); if (name != NULL && !valid_function_name(name)) { yr_free(name); thunks32++; func_idx++; continue; } if (name != NULL || has_ordinal == 1) { IMPORT_FUNCTION* imported_func = (IMPORT_FUNCTION*) yr_calloc( 1, sizeof(IMPORT_FUNCTION)); if (imported_func == NULL) { yr_free(name); } else { imported_func->name = name; imported_func->ordinal = ordinal; imported_func->has_ordinal = has_ordinal; imported_func->rva = rva_address; imported_func->next = NULL; if (head == NULL) head = imported_func; if (tail != NULL) tail->next = imported_func; tail = imported_func; (*num_function_imports)++; } } thunks32++; func_idx++; } } return head; } // // In Windows PE files, any printable character including 0x20 and above is // allowed. The only exceptions are characters that are invalid for file names // in Windows, which are "*<>?|. While they still can be present in the import // directory, such module can never be present in Windows, so we can treat them // as invalid. // // Explicit: The above also applies to slash, backslash (these form a relative // path in a subdirectory, which is allowed in the import directory) and colon // (which forms a file name with an Alternate Data Stream "test:file.dll" - also // allowed). // // Proof of concept: https://github.com/ladislav-zezula/ImportTest // // Samples // ------- // f561d60bff4342e529b2c793e216b73a72e6256f90ab24c3cc460646371130ca (imports // "test/file.dll") // b7f7b8a001769eb0f9c36cb27626b62cabdca9a716a222066028fcd206244b40 (imports // "test\file.dll") // 94cfb8223132da0a76f9dfbd35a29ab78e5806651758650292ab9c7baf2c0bc2 (imports // "test:file.dll") // eb2e2c443840276afe095fff05a3a24c00e610ac0e020233d6cd7a0b0b340fb1 (the // imported DLL) // static int pe_valid_dll_name(const char* dll_name, size_t n) { const unsigned char* c = (const unsigned char*) dll_name; size_t l = 0; while (l < n && *c != '\0') { if (*c < ' ' || *c > 0x7e || *c == '\"' || *c == '*' || *c == '<' || *c == '>' || *c == '?' || *c == '|') { return false; } c++; l++; } return (l > 0 && l < n); } void pe_set_imports( PE* pe, IMPORTED_DLL* dll, const char* dll_name, const char* dll_number_of_functions, const char* fun_name, const char* fun_ordinal, const char* rva) { int dll_cnt = 0; for (; dll != NULL; dll = dll->next, dll_cnt++) { int fun_cnt = 0; for (IMPORT_FUNCTION* func = dll->functions; func != NULL; func = func->next, fun_cnt++) { yr_set_string(func->name, pe->object, fun_name, dll_cnt, fun_cnt); if (func->has_ordinal) yr_set_integer( func->ordinal, pe->object, fun_ordinal, dll_cnt, fun_cnt); else yr_set_integer(YR_UNDEFINED, pe->object, fun_ordinal, dll_cnt, fun_cnt); if (func->rva) yr_set_integer(func->rva, pe->object, rva, dll_cnt, fun_cnt); else yr_set_integer(YR_UNDEFINED, pe->object, rva, dll_cnt, fun_cnt); } yr_set_string(dll->name, pe->object, dll_name, dll_cnt); yr_set_integer(fun_cnt, pe->object, dll_number_of_functions, dll_cnt); } } // // Walk the imports and collect relevant information. It is used in the // "imports" function for comparison and in the "imphash" function for // calculation. // static IMPORTED_DLL* pe_parse_imports(PE* pe) { int64_t offset; int parsed_imports = 0; // Number of parsed DLLs int num_imports = 0; // Number of imported DLLs int num_function_imports = 0; // Total number of functions imported IMPORTED_DLL* head = NULL; IMPORTED_DLL* tail = NULL; PIMAGE_IMPORT_DESCRIPTOR imports; PIMAGE_DATA_DIRECTORY directory; // Default to 0 imports until we know there are any yr_set_integer(0, pe->object, "number_of_imports"); yr_set_integer(0, pe->object, "number_of_imported_functions"); directory = pe_get_directory_entry(pe, IMAGE_DIRECTORY_ENTRY_IMPORT); if (directory == NULL) return NULL; if (yr_le32toh(directory->VirtualAddress) == 0) return NULL; offset = pe_rva_to_offset(pe, yr_le32toh(directory->VirtualAddress)); if (offset < 0) return NULL; imports = (PIMAGE_IMPORT_DESCRIPTOR) (pe->data + offset); while (struct_fits_in_pe(pe, imports, IMAGE_IMPORT_DESCRIPTOR) && yr_le32toh(imports->Name) != 0 && parsed_imports < MAX_PE_IMPORTS) { parsed_imports++; int64_t offset = pe_rva_to_offset(pe, yr_le32toh(imports->Name)); if (offset >= 0) { IMPORTED_DLL* imported_dll; char* dll_name = (char*) (pe->data + offset); if (!pe_valid_dll_name( dll_name, yr_min( // DLL names longer than MAX_IMPORT_DLL_NAME_LENGTH // are considered invalid. pe->data_size - (size_t) offset, MAX_IMPORT_DLL_NAME_LENGTH))) { imports++; continue; } imported_dll = (IMPORTED_DLL*) yr_calloc(1, sizeof(IMPORTED_DLL)); if (imported_dll != NULL) { IMPORT_FUNCTION* functions = pe_parse_import_descriptor( pe, imports, dll_name, &num_function_imports); if (functions != NULL) { imported_dll->name = yr_strdup(dll_name); imported_dll->functions = functions; imported_dll->next = NULL; if (head == NULL) head = imported_dll; if (tail != NULL) tail->next = imported_dll; tail = imported_dll; num_imports++; } else { yr_free(imported_dll); } } } imports++; } yr_set_integer(num_imports, pe->object, "number_of_imports"); yr_set_integer( num_function_imports, pe->object, "number_of_imported_functions"); pe_set_imports( pe, head, "import_details[%i].library_name", "import_details[%i].number_of_functions", "import_details[%i].functions[%i].name", "import_details[%i].functions[%i].ordinal", "import_details[%i].functions[%i].rva"); return head; } // Delay-import descriptors made by MS Visual C++ 6.0 have old format // of delay import directory, where all entries are VAs (as opposite to RVAs // from newer MS compilers). We convert the delay-import directory entries to // RVAs by checking the lowest bit in the delay-import descriptor's Attributes // value uint64_t pe_normalize_delay_import_value( uint64_t image_base, uint64_t virtual_address) { // Ignore zero items if (virtual_address != 0) { // Sample: 0fc4cb0620f95bdd624f2c78eea4d2b59594244c6671cf249526adf2f2cb71ec // Contains artificially created delay import directory with incorrect // values: // // Attributes 0x00000000 <-- Old MS delay import // record, contains VAs NameRva 0x004010e6 // ModuleHandleRva 0x00000000 // DelayImportAddressTableRva 0x00001140 <-- WRONG! This is an RVA // DelayImportNameTableRva 0x004010c0 // BoundDelayImportTableRva 0x00000000 // ... if (virtual_address > image_base) { virtual_address = virtual_address - image_base; } } return virtual_address; } int pe_is_termination_delay_import_entry( PIMAGE_DELAYLOAD_DESCRIPTOR importDescriptor) { return ( importDescriptor->Attributes.AllAttributes == 0 && importDescriptor->DllNameRVA == 0 && importDescriptor->ModuleHandleRVA == 0 && importDescriptor->ImportAddressTableRVA == 0 && importDescriptor->ImportNameTableRVA == 0 && importDescriptor->BoundImportAddressTableRVA == 0 && importDescriptor->UnloadInformationTableRVA == 0 && importDescriptor->TimeDateStamp == 0); } char* pe_parse_delay_import_dll_name(PE* pe, uint64_t rva) { const int64_t offset = pe_rva_to_offset(pe, rva); if (offset < 0) return NULL; char* dll_name = (char*) (pe->data + offset); if (!pe_valid_dll_name(dll_name, pe->data_size - (size_t) offset)) return NULL; return yr_strdup(dll_name); } uint64_t pe_parse_delay_import_pointer( PE* pe, uint64_t pointerSize, uint64_t rva) { const int64_t offset = pe_rva_to_offset(pe, rva); if (offset < 0) return YR_UNDEFINED; const uint8_t* data = pe->data + offset; if (!fits_in_pe(pe, data, pointerSize)) return YR_UNDEFINED; if (IS_64BITS_PE(pe)) return yr_le64toh(*(uint64_t*) data); else return yr_le32toh(*(uint32_t*) data); } static void* pe_parse_delayed_imports(PE* pe) { int64_t offset; uint64_t num_imports = 0; // Number of imported DLLs uint64_t num_function_imports = 0; // Total number of functions imported uint64_t image_base = OptionalHeader(pe, ImageBase); uint64_t size_of_image = OptionalHeader(pe, SizeOfImage); uint64_t pointer_size = (IS_64BITS_PE(pe)) ? 8 : 4; uint64_t ordinal_mask = (IS_64BITS_PE(pe)) ? IMAGE_ORDINAL_FLAG64 : IMAGE_ORDINAL_FLAG32; IMPORTED_DLL* head_dll = NULL; IMPORTED_DLL* tail_dll = NULL; IMPORT_FUNCTION* head_fun = NULL; IMPORT_FUNCTION* tail_fun = NULL; PIMAGE_DELAYLOAD_DESCRIPTOR import_descriptor = NULL; PIMAGE_DATA_DIRECTORY directory = NULL; // Default to 0 imports until we know there are any yr_set_integer(0, pe->object, "number_of_delayed_imports"); yr_set_integer(0, pe->object, "number_of_delayed_imported_functions"); directory = pe_get_directory_entry(pe, IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT); if (directory == NULL) return NULL; if (yr_le32toh(directory->VirtualAddress) == 0) return NULL; offset = pe_rva_to_offset(pe, yr_le32toh(directory->VirtualAddress)); if (offset < 0) return NULL; import_descriptor = (PIMAGE_DELAYLOAD_DESCRIPTOR) (pe->data + offset); for (; struct_fits_in_pe(pe, import_descriptor, IMAGE_DELAYLOAD_DESCRIPTOR); import_descriptor++) { // Check for the termination entry if (pe_is_termination_delay_import_entry(import_descriptor)) break; DWORD Attributes = yr_le32toh(import_descriptor->Attributes.AllAttributes); DWORD DllNameRVA = yr_le32toh(import_descriptor->DllNameRVA); DWORD ModuleHandleRVA = yr_le32toh(import_descriptor->ModuleHandleRVA); DWORD ImportAddressTableRVA = yr_le32toh( import_descriptor->ImportAddressTableRVA); DWORD ImportNameTableRVA = yr_le32toh( import_descriptor->ImportNameTableRVA); DWORD BoundImportAddressTableRVA = yr_le32toh( import_descriptor->BoundImportAddressTableRVA); DWORD UnloadInformationTableRVA = yr_le32toh( import_descriptor->UnloadInformationTableRVA); // Valid delayed import entry starts either with 0 or 0x01. // We strict require one of the valid values here if (Attributes > 0x1) break; // Convert older (MS Visual C++ 6.0) delay-import descriptor to newer one. // These delay-import descriptors are distinguishable by lowest bit in // rec.Attributes to be zero. Sample: // 2775d97f8bdb3311ace960a42eee35dbec84b9d71a6abbacb26c14e83f5897e4 if (!IS_64BITS_PE(pe) && !Attributes) { DllNameRVA = (DWORD) pe_normalize_delay_import_value( image_base, DllNameRVA); ModuleHandleRVA = (DWORD) pe_normalize_delay_import_value( image_base, ModuleHandleRVA); ImportAddressTableRVA = (DWORD) pe_normalize_delay_import_value( image_base, ImportAddressTableRVA); ImportNameTableRVA = (DWORD) pe_normalize_delay_import_value( image_base, ImportNameTableRVA); BoundImportAddressTableRVA = (DWORD) pe_normalize_delay_import_value( image_base, BoundImportAddressTableRVA); UnloadInformationTableRVA = (DWORD) pe_normalize_delay_import_value( image_base, UnloadInformationTableRVA); } // Stop on blatantly invalid delay import entries (old PELIB behavior) if (ImportNameTableRVA >= size_of_image || ImportAddressTableRVA >= size_of_image || DllNameRVA < sizeof(IMAGE_DOS_HEADER) || ImportNameTableRVA < sizeof(IMAGE_DOS_HEADER)) break; char* dll_name = pe_parse_delay_import_dll_name(pe, DllNameRVA); if (dll_name == NULL) continue; IMPORTED_DLL* imported_dll = (IMPORTED_DLL*) yr_calloc( 1, sizeof(IMPORTED_DLL)); if (imported_dll == NULL) { yr_free(dll_name); continue; } imported_dll->name = dll_name; imported_dll->next = NULL; imported_dll->functions = NULL; head_fun = tail_fun = NULL; uint64_t name_rva = ImportNameTableRVA; uint64_t func_rva = ImportAddressTableRVA; for (;;) { uint64_t nameAddress = pe_parse_delay_import_pointer( pe, pointer_size, name_rva); uint64_t funcAddress = pe_parse_delay_import_pointer( pe, pointer_size, func_rva); // Value of YR_UNDEFINED means that value is outside of pe->data if (nameAddress == YR_UNDEFINED || funcAddress == YR_UNDEFINED) break; // Value of zero means that this is the end of the bound import name table if (nameAddress == 0 || funcAddress == 0) break; char* func_name; uint8_t has_ordinal = 0; // Check name address. It could be ordinal, VA or RVA if (!(nameAddress & ordinal_mask)) { // Convert name address to RVA, if needed if (!Attributes) nameAddress = pe_normalize_delay_import_value( image_base, nameAddress); offset = pe_rva_to_offset(pe, nameAddress + sizeof(uint16_t)); if (offset < 0) { name_rva += pointer_size; func_rva += pointer_size; continue; } func_name = (char*) yr_strndup( (char*) (pe->data + offset), yr_min(available_space(pe, (char*) (pe->data + offset)), 512)); } else { // If imported by ordinal. Lookup the ordinal. func_name = ord_lookup(dll_name, nameAddress & 0xFFFF); has_ordinal = 1; } IMPORT_FUNCTION* imported_func = (IMPORT_FUNCTION*) yr_malloc( sizeof(IMPORT_FUNCTION)); if (imported_func == NULL) break; imported_func->name = func_name; imported_func->rva = func_rva; imported_func->has_ordinal = has_ordinal; imported_func->ordinal = (has_ordinal) ? nameAddress & 0xFFFF : 0; imported_func->next = NULL; num_function_imports++; name_rva += pointer_size; func_rva += pointer_size; if (head_fun == NULL) head_fun = imported_func; if (tail_fun != NULL) tail_fun->next = imported_func; tail_fun = imported_func; } num_imports++; imported_dll->functions = head_fun; if (head_dll == NULL) head_dll = imported_dll; if (tail_dll != NULL) tail_dll->next = imported_dll; tail_dll = imported_dll; } yr_set_integer(num_imports, pe->object, "number_of_delayed_imports"); yr_set_integer( num_function_imports, pe->object, "number_of_delayed_imported_functions"); pe_set_imports( pe, head_dll, "delayed_import_details[%i].library_name", "delayed_import_details[%i].number_of_functions", "delayed_import_details[%i].functions[%i].name", "delayed_import_details[%i].functions[%i].ordinal", "delayed_import_details[%i].functions[%i].rva"); return head_dll; } // // Walk the exports and collect relevant information. It is used in the // "exports" function for comparison. // static void pe_parse_exports(PE* pe) { PIMAGE_DATA_DIRECTORY directory; PIMAGE_EXPORT_DIRECTORY exports; int64_t offset; int64_t export_start; uint32_t i, j; uint32_t number_of_exports; uint32_t number_of_names; uint32_t ordinal_base; size_t export_size; size_t remaining; size_t name_len; uint32_t exp_sz = 0; DWORD* names = NULL; WORD* ordinals = NULL; DWORD* function_addrs = NULL; // If not a PE file, return YR_UNDEFINED if (pe == NULL) return; // Default to 0 exports until we know there are any yr_set_integer(0, pe->object, "number_of_exports"); directory = pe_get_directory_entry(pe, IMAGE_DIRECTORY_ENTRY_EXPORT); if (directory == NULL) return; if (yr_le32toh(directory->VirtualAddress) == 0) return; offset = pe_rva_to_offset(pe, yr_le32toh(directory->VirtualAddress)); if (offset < 0) return; export_start = offset; export_size = yr_le32toh(directory->Size); exports = (PIMAGE_EXPORT_DIRECTORY) (pe->data + offset); if (!struct_fits_in_pe(pe, exports, IMAGE_EXPORT_DIRECTORY)) return; number_of_exports = yr_min( yr_le32toh(exports->NumberOfFunctions), MAX_PE_EXPORTS); ordinal_base = yr_le32toh(exports->Base); yr_set_integer( yr_le32toh(exports->TimeDateStamp), pe->object, "export_timestamp"); offset = pe_rva_to_offset(pe, yr_le32toh(exports->Name)); if (offset > 0) { remaining = pe->data_size - (size_t) offset; name_len = strnlen((char*) (pe->data + offset), remaining); yr_set_sized_string( (char*) (pe->data + offset), name_len, pe->object, "dll_name"); } if (number_of_exports * sizeof(DWORD) > pe->data_size - offset) return; if (yr_le32toh(exports->NumberOfNames) > 0) { offset = pe_rva_to_offset(pe, yr_le32toh(exports->AddressOfNames)); if (offset < 0) return; if (yr_le32toh(exports->NumberOfNames) * sizeof(DWORD) > pe->data_size - offset) return; names = (DWORD*) (pe->data + offset); } offset = pe_rva_to_offset(pe, yr_le32toh(exports->AddressOfNameOrdinals)); if (offset < 0) return; ordinals = (WORD*) (pe->data + offset); if (available_space(pe, ordinals) < sizeof(WORD) * number_of_exports) return; offset = pe_rva_to_offset(pe, yr_le32toh(exports->AddressOfFunctions)); if (offset < 0) return; function_addrs = (DWORD*) (pe->data + offset); if (available_space(pe, function_addrs) < sizeof(DWORD) * number_of_exports) return; number_of_names = yr_min( yr_le32toh(yr_le32toh(exports->NumberOfNames)), number_of_exports); // Mapping out the exports is a bit janky. We start with the export address // array. The index from that array plus the ordinal base is the ordinal for // that export. To find the name we walk the ordinal array looking for a value // that matches our index. If one exists we look up the corresponding RVA from // the names array and follow it to get the name. If one does not exist then // the export has no name. // // Ordinal base: 5 // 0 1 2 // Address array: [ 0x00000011 | 0x00000022 | 0x00000033 ] // 0 1 2 // Ordinal array: [ 0x0000 | 0x0002 | 0x0001 ] // 0 1 // Names array: [ 0x00000044 | 0x00000055 ] // // The function at RVA 0x00000011 (index 0) has ordinal 5 (base + index). The // index can be found in position 0 in the ordinal array. Using 0 to index // into the name array gives us an RVA (0x00000044) which we can follow to get // the name. // // The function at RVA 0x00000022 (index 1) has ordinal 6 (base + index). The // index can be found in position 2 in the ordinal array. 2 is out of bounds // for the names array so this function is exported without a name. // // The function at RVA 0x00000033 (index 2) has ordinal 7 (base + index). The // index can be found in position 1 in the ordinal array. Using 1 to index // into the name array gives us an RVA (0x00000055) which we can follow to get // the name. // // If the RVA from the address array is within the export directory it is a // forwarder RVA and points to a NULL terminated ASCII string. for (i = 0; i < number_of_exports; i++) { yr_set_integer( ordinal_base + i, pe->object, "export_details[%i].ordinal", exp_sz); yr_set_integer( yr_le32toh(function_addrs[i]), pe->object, "export_details[%i].rva", exp_sz); // Don't check for a failure here since some packers make this an invalid // value. offset = pe_rva_to_offset(pe, yr_le32toh(function_addrs[i])); if (offset > export_start && offset < export_start + export_size) { remaining = pe->data_size - (size_t) offset; name_len = strnlen((char*) (pe->data + offset), remaining); yr_set_sized_string( (char*) (pe->data + offset), yr_min(name_len, MAX_EXPORT_NAME_LENGTH), pe->object, "export_details[%i].forward_name", exp_sz); } else { if (offset < 0) offset = YR_UNDEFINED; yr_set_integer(offset, pe->object, "export_details[%i].offset", exp_sz); } if (names != NULL) { for (j = 0; j < number_of_exports; j++) { if (yr_le16toh(ordinals[j]) == i && j < number_of_names) { offset = pe_rva_to_offset(pe, yr_le32toh(names[j])); if (offset > 0) { remaining = pe->data_size - (size_t) offset; name_len = strnlen((char*) (pe->data + offset), remaining); yr_set_sized_string( (char*) (pe->data + offset), yr_min(name_len, MAX_EXPORT_NAME_LENGTH), pe->object, "export_details[%i].name", exp_sz); } break; } } } exp_sz++; } yr_set_integer(exp_sz, pe->object, "number_of_exports"); } // BoringSSL (https://boringssl.googlesource.com/boringssl/) doesn't support // some features used in pe_parse_certificates, if you are using BoringSSL // instead of OpenSSL you should define BORINGSSL for YARA to compile properly, // but you won't have signature-related features in the PE module. #if defined(HAVE_LIBCRYPTO) && !defined(BORINGSSL) #define write_certificate(cert, pe, fmt, ...) \ do \ { \ char thumbprint_ascii[YR_SHA1_LEN * 2 + 1]; \ for (int j = 0; j < cert->sha1.len; ++j) \ sprintf(thumbprint_ascii + (j * 2), "%02x", cert->sha1.data[j]); \ \ yr_set_string( \ (char*) thumbprint_ascii, pe->object, fmt ".thumbprint", __VA_ARGS__); \ \ yr_set_string(cert->issuer, pe->object, fmt ".issuer", __VA_ARGS__); \ yr_set_string(cert->subject, pe->object, fmt ".subject", __VA_ARGS__); \ /* Versions are zero based, so add one. */ \ yr_set_integer( \ cert->version + 1, pe->object, fmt ".version", __VA_ARGS__); \ yr_set_string(cert->sig_alg, pe->object, fmt ".algorithm", __VA_ARGS__); \ yr_set_string( \ cert->sig_alg_oid, pe->object, fmt ".algorithm_oid", __VA_ARGS__); \ yr_set_string(cert->serial, pe->object, fmt ".serial", __VA_ARGS__); \ yr_set_integer( \ cert->not_before, pe->object, fmt ".not_before", __VA_ARGS__); \ yr_set_integer( \ cert->not_after, pe->object, fmt ".not_after", __VA_ARGS__); \ } while (0) void _process_authenticode( PE* pe, AuthenticodeArray* auth_array, int* sig_count) { if (!auth_array || !auth_array->count) return; bool signature_valid = false; for (size_t i = 0; i < auth_array->count; ++i) { const Authenticode* authenticode = auth_array->signatures[i]; if (authenticode->verify_flags == AUTHENTICODE_VFY_CANT_PARSE) continue; if (authenticode->verify_flags == AUTHENTICODE_VFY_WRONG_PKCS7_TYPE) continue; if (authenticode->verify_flags == AUTHENTICODE_VFY_NO_SIGNER_INFO) continue; if (authenticode->verify_flags == AUTHENTICODE_VFY_NO_SIGNER_CERT) continue; if (authenticode->verify_flags == AUTHENTICODE_VFY_INTERNAL_ERROR) continue; bool verified = authenticode->verify_flags == AUTHENTICODE_VFY_VALID; /* If any signature is valid -> file is correctly signed */ signature_valid |= verified; yr_set_integer(verified, pe->object, "signatures[%i].verified", *sig_count); yr_set_string( authenticode->digest_alg, pe->object, "signatures[%i].digest_alg", *sig_count); if (authenticode->digest.data) { char* digest_ascii = yr_malloc(authenticode->digest.len * 2 + 1); for (int j = 0; j < authenticode->digest.len; ++j) sprintf(digest_ascii + (j * 2), "%02x", authenticode->digest.data[j]); yr_set_string( digest_ascii, pe->object, "signatures[%i].digest", *sig_count); yr_free(digest_ascii); } if (authenticode->file_digest.data) { char* digest_ascii = yr_malloc(authenticode->file_digest.len * 2 + 1); for (int j = 0; j < authenticode->file_digest.len; ++j) sprintf( digest_ascii + (j * 2), "%02x", authenticode->file_digest.data[j]); yr_set_string( digest_ascii, pe->object, "signatures[%i].file_digest", *sig_count); yr_free(digest_ascii); } yr_set_integer( authenticode->certs ? authenticode->certs->count : 0, pe->object, "signatures[%i].number_of_certificates", *sig_count); if (authenticode->certs) { for (int k = 0; k < authenticode->certs->count; ++k) { write_certificate( authenticode->certs->certs[k], pe, "signatures[%i].certificates[%i]", *sig_count, k); } } const Signer* signer = authenticode->signer; if (signer) { /* For compatibility with previous YARA rules, write information * about signing certificate in the same way */ if (signer->chain && signer->chain->count >= 1) { const Certificate* sign_cert = signer->chain->certs[0]; write_certificate(sign_cert, pe, "signatures[%i]", *sig_count); } yr_set_string( signer->program_name, pe->object, "signatures[%i].signer_info.program_name", *sig_count); yr_set_string( signer->digest_alg, pe->object, "signatures[%i].signer_info.digest_alg", *sig_count); if (signer->digest.data) { char* digest_ascii = yr_malloc(signer->digest.len * 2 + 1); for (int j = 0; j < signer->digest.len; ++j) sprintf(digest_ascii + (j * 2), "%02x", signer->digest.data[j]); yr_set_string( digest_ascii, pe->object, "signatures[%i].signer_info.digest", *sig_count); yr_free(digest_ascii); } yr_set_integer( signer->chain ? signer->chain->count : 0, pe->object, "signatures[%i].signer_info.length_of_chain", *sig_count); if (signer->chain) { for (int k = 0; k < signer->chain->count; ++k) { write_certificate( signer->chain->certs[k], pe, "signatures[%i].signer_info.chain[%i]", *sig_count, k); } } } yr_set_integer( authenticode->countersigs ? authenticode->countersigs->count : 0, pe->object, "signatures[%i].number_of_countersignatures", *sig_count); if (authenticode->countersigs) { for (int j = 0; j < authenticode->countersigs->count; ++j) { const Countersignature* counter = authenticode->countersigs->counters[j]; yr_set_integer( counter->verify_flags == COUNTERSIGNATURE_VFY_VALID, pe->object, "signatures[%i].countersignatures[%i].verified", *sig_count, j); yr_set_string( counter->digest_alg, pe->object, "signatures[%i].countersignatures[%i].digest_alg", *sig_count, j); yr_set_integer( counter->sign_time, pe->object, "signatures[%i].countersignatures[%i].sign_time", *sig_count, j); if (counter->digest.data) { char* digest_ascii = yr_malloc(counter->digest.len * 2 + 1); for (int j = 0; j < counter->digest.len; ++j) sprintf(digest_ascii + (j * 2), "%02x", counter->digest.data[j]); yr_set_string( digest_ascii, pe->object, "signatures[%i].countersignatures[%i].digest", *sig_count, j); yr_free(digest_ascii); } yr_set_integer( counter->chain ? counter->chain->count : 0, pe->object, "signatures[%i].countersignatures[%i].length_of_chain", *sig_count, j); if (counter->chain) { for (int k = 0; k < counter->chain->count; ++k) { write_certificate( counter->chain->certs[k], pe, "signatures[%i].countersignatures[%i].chain[%i]", *sig_count, j, k); } } } } (*sig_count)++; } yr_set_integer(signature_valid, pe->object, "is_signed"); } static void pe_parse_certificates(PE* pe) { int counter = 0; // Default to 0 signatures until we know otherwise. yr_set_integer(0, pe->object, "number_of_signatures"); // Default to not signed until we know otherwise. yr_set_integer(0, pe->object, "is_signed"); PIMAGE_DATA_DIRECTORY directory = pe_get_directory_entry( pe, IMAGE_DIRECTORY_ENTRY_SECURITY); if (directory == NULL) return; // directory->VirtualAddress is a file offset. Don't call pe_rva_to_offset(). if (yr_le32toh(directory->VirtualAddress) == 0 || yr_le32toh(directory->VirtualAddress) > pe->data_size || yr_le32toh(directory->Size) > pe->data_size || yr_le32toh(directory->VirtualAddress) + yr_le32toh(directory->Size) > pe->data_size) { return; } AuthenticodeArray* auth_array = parse_authenticode(pe->data, pe->data_size); _process_authenticode(pe, auth_array, &counter); authenticode_array_free(auth_array); yr_set_integer(counter, pe->object, "number_of_signatures"); } #endif // defined(HAVE_LIBCRYPTO) const char* pe_get_section_full_name( PE* pe, const char* section_name, uint64_t section_name_length, uint64_t* section_full_name_length) { // section_name is an 8-byte, null-padded UTF-8 encoded string. If the string // is exactly 8 characters long, there is no terminating null. For longer // names, this field contains a slash (/) that is followed by an ASCII // representation of a decimal number that is an offset into the string table. // Sample: 2e9c671b8a0411f2b397544b368c44d7f095eb395779de0ad1ac946914dfa34c // Check if any param is NULL if (pe == NULL || section_name == NULL || section_full_name_length == NULL) return NULL; // Set length to zero *section_full_name_length = 0; // Offset and number of records in coff table uint64_t coff_offset = yr_le32toh( pe->header->FileHeader.PointerToSymbolTable); uint64_t coff_number = yr_le32toh(pe->header->FileHeader.NumberOfSymbols); // If section name start with '/' and file contain coff table then section // name is stored in string table if (coff_offset == 0 || section_name[0] != '/') { *section_full_name_length = section_name_length; return section_name; } // Calculate offset of string table (String table is immediately after coff // table) uint64_t string_offset = coff_offset + coff_number * sizeof(IMAGE_SYMBOL); uint64_t string_index = 0; // Calculate string index/offset in string table for (int i = 1; i < IMAGE_SIZEOF_SHORT_NAME && isdigit(section_name[i]); i++) string_index = (string_index * 10) + (section_name[i] - '0'); // Calculate string pointer const char* string = (char*) (pe->data + string_offset + string_index); // Check string for (uint64_t len = 0; fits_in_pe(pe, string, len + 1); len++) { // Prevent sign extension to 32-bits on bytes > 0x7F // The result negative integer would cause assert in MSVC debug version of // isprint() unsigned int one_char = (unsigned char) (string[len]); // Valid string if (one_char == 0) { *section_full_name_length = len; return string; } // string contain unprintable character if (!isprint(one_char)) return NULL; } // String do not fit into pe file return NULL; } static void pe_parse_header(PE* pe, uint64_t base_address, int flags) { PIMAGE_SECTION_HEADER section; PIMAGE_DATA_DIRECTORY data_dir; char section_name[IMAGE_SIZEOF_SHORT_NAME + 1]; int sect_name_length; uint16_t scount; uint32_t ddcount; uint64_t highest_sec_siz = 0; uint64_t highest_sec_ofs = 0; uint64_t section_end; uint64_t last_section_end; yr_set_integer(1, pe->object, "is_pe"); yr_set_integer( yr_le16toh(pe->header->FileHeader.Machine), pe->object, "machine"); yr_set_integer( yr_le16toh(pe->header->FileHeader.NumberOfSections), pe->object, "number_of_sections"); yr_set_integer( yr_le32toh(pe->header->FileHeader.TimeDateStamp), pe->object, "timestamp"); yr_set_integer( yr_le32toh(pe->header->FileHeader.PointerToSymbolTable), pe->object, "pointer_to_symbol_table"); yr_set_integer( yr_le32toh(pe->header->FileHeader.NumberOfSymbols), pe->object, "number_of_symbols"); yr_set_integer( yr_le16toh(pe->header->FileHeader.SizeOfOptionalHeader), pe->object, "size_of_optional_header"); yr_set_integer( yr_le16toh(pe->header->FileHeader.Characteristics), pe->object, "characteristics"); yr_set_integer( flags & SCAN_FLAGS_PROCESS_MEMORY ? base_address + yr_le32toh(OptionalHeader(pe, AddressOfEntryPoint)) : pe_rva_to_offset( pe, yr_le32toh(OptionalHeader(pe, AddressOfEntryPoint))), pe->object, "entry_point"); yr_set_integer( yr_le32toh(OptionalHeader(pe, AddressOfEntryPoint)), pe->object, "entry_point_raw"); yr_set_integer( IS_64BITS_PE(pe) ? yr_le64toh(OptionalHeader(pe, ImageBase)) : yr_le32toh(OptionalHeader(pe, ImageBase)), pe->object, "image_base"); yr_set_integer( yr_le32toh(OptionalHeader(pe, NumberOfRvaAndSizes)), pe->object, "number_of_rva_and_sizes"); yr_set_integer( yr_le16toh(OptionalHeader(pe, Magic)), pe->object, "opthdr_magic"); yr_set_integer( OptionalHeader(pe, MajorLinkerVersion), pe->object, "linker_version.major"); yr_set_integer( OptionalHeader(pe, MinorLinkerVersion), pe->object, "linker_version.minor"); yr_set_integer( yr_le32toh(OptionalHeader(pe, SizeOfCode)), pe->object, "size_of_code"); yr_set_integer( yr_le32toh(OptionalHeader(pe, SizeOfInitializedData)), pe->object, "size_of_initialized_data"); yr_set_integer( yr_le32toh(OptionalHeader(pe, SizeOfUninitializedData)), pe->object, "size_of_uninitialized_data"); yr_set_integer( yr_le32toh(OptionalHeader(pe, BaseOfCode)), pe->object, "base_of_code"); if (!IS_64BITS_PE(pe)) { yr_set_integer( yr_le32toh(pe->header->OptionalHeader.BaseOfData), pe->object, "base_of_data"); } yr_set_integer( yr_le32toh(OptionalHeader(pe, SectionAlignment)), pe->object, "section_alignment"); yr_set_integer( yr_le32toh(OptionalHeader(pe, FileAlignment)), pe->object, "file_alignment"); yr_set_integer( yr_le16toh(OptionalHeader(pe, MajorOperatingSystemVersion)), pe->object, "os_version.major"); yr_set_integer( yr_le16toh(OptionalHeader(pe, MinorOperatingSystemVersion)), pe->object, "os_version.minor"); yr_set_integer( yr_le16toh(OptionalHeader(pe, MajorImageVersion)), pe->object, "image_version.major"); yr_set_integer( yr_le16toh(OptionalHeader(pe, MinorImageVersion)), pe->object, "image_version.minor"); yr_set_integer( yr_le16toh(OptionalHeader(pe, MajorSubsystemVersion)), pe->object, "subsystem_version.major"); yr_set_integer( yr_le16toh(OptionalHeader(pe, MinorSubsystemVersion)), pe->object, "subsystem_version.minor"); yr_set_integer( yr_le32toh(OptionalHeader(pe, Win32VersionValue)), pe->object, "win32_version_value"); yr_set_integer( yr_le32toh(OptionalHeader(pe, SizeOfImage)), pe->object, "size_of_image"); yr_set_integer( yr_le32toh(OptionalHeader(pe, SizeOfHeaders)), pe->object, "size_of_headers"); yr_set_integer( yr_le32toh(OptionalHeader(pe, CheckSum)), pe->object, "checksum"); yr_set_integer( yr_le16toh(OptionalHeader(pe, Subsystem)), pe->object, "subsystem"); yr_set_integer( yr_le16toh(OptionalHeader(pe, DllCharacteristics)), pe->object, "dll_characteristics"); yr_set_integer( IS_64BITS_PE(pe) ? yr_le64toh(OptionalHeader(pe, SizeOfStackReserve)) : yr_le32toh(OptionalHeader(pe, SizeOfStackReserve)), pe->object, "size_of_stack_reserve"); yr_set_integer( IS_64BITS_PE(pe) ? yr_le64toh(OptionalHeader(pe, SizeOfStackCommit)) : yr_le32toh(OptionalHeader(pe, SizeOfStackCommit)), pe->object, "size_of_stack_commit"); yr_set_integer( IS_64BITS_PE(pe) ? yr_le64toh(OptionalHeader(pe, SizeOfHeapReserve)) : yr_le32toh(OptionalHeader(pe, SizeOfHeapReserve)), pe->object, "size_of_heap_reserve"); yr_set_integer( IS_64BITS_PE(pe) ? yr_le64toh(OptionalHeader(pe, SizeOfHeapCommit)) : yr_le32toh(OptionalHeader(pe, SizeOfHeapCommit)), pe->object, "size_of_heap_commit"); yr_set_integer( yr_le32toh(OptionalHeader(pe, LoaderFlags)), pe->object, "loader_flags"); data_dir = IS_64BITS_PE(pe) ? pe->header64->OptionalHeader.DataDirectory : pe->header->OptionalHeader.DataDirectory; ddcount = yr_le32toh(OptionalHeader(pe, NumberOfRvaAndSizes)); ddcount = yr_min(ddcount, IMAGE_NUMBEROF_DIRECTORY_ENTRIES); for (int i = 0; i < ddcount; i++) { if (!struct_fits_in_pe(pe, data_dir, IMAGE_DATA_DIRECTORY)) break; yr_set_integer( yr_le32toh(data_dir->VirtualAddress), pe->object, "data_directories[%i].virtual_address", i); yr_set_integer( yr_le32toh(data_dir->Size), pe->object, "data_directories[%i].size", i); data_dir++; } pe_iterate_resources( pe, (RESOURCE_CALLBACK_FUNC) pe_collect_resources, (void*) pe); yr_set_integer(pe->resources, pe->object, "number_of_resources"); yr_set_integer(pe->version_infos, pe->object, "number_of_version_infos"); section = IMAGE_FIRST_SECTION(pe->header); scount = yr_min( yr_le16toh(pe->header->FileHeader.NumberOfSections), MAX_PE_SECTIONS); for (int i = 0; i < scount; i++) { if (!struct_fits_in_pe(pe, section, IMAGE_SECTION_HEADER)) break; memcpy(section_name, section->Name, IMAGE_SIZEOF_SHORT_NAME); section_name[IMAGE_SIZEOF_SHORT_NAME] = '\0'; // Basically do rstrip('\0'), find the rightmost non-null character. // Samples like // 0043812838495a45449a0ac61a81b9c16eddca1ad249fb4f7fdb1c4505e9bb34 contain // sections with additional characters after the first null. for (sect_name_length = IMAGE_SIZEOF_SHORT_NAME - 1; sect_name_length >= 0; --sect_name_length) { if (section_name[sect_name_length] != '\0') break; } uint64_t sect_full_name_length = 0; const char* full_section_name = pe_get_section_full_name( pe, section_name, sect_name_length + 1, §_full_name_length); yr_set_sized_string( (char*) section_name, sect_name_length + 1, pe->object, "sections[%i].name", i); yr_set_sized_string( full_section_name, sect_full_name_length, pe->object, "sections[%i].full_name", i); yr_set_integer( yr_le32toh(section->Characteristics), pe->object, "sections[%i].characteristics", i); yr_set_integer( yr_le32toh(section->SizeOfRawData), pe->object, "sections[%i].raw_data_size", i); yr_set_integer( yr_le32toh(section->PointerToRawData), pe->object, "sections[%i].raw_data_offset", i); yr_set_integer( yr_le32toh(section->VirtualAddress), pe->object, "sections[%i].virtual_address", i); yr_set_integer( yr_le32toh(section->Misc.VirtualSize), pe->object, "sections[%i].virtual_size", i); yr_set_integer( yr_le32toh(section->PointerToRelocations), pe->object, "sections[%i].pointer_to_relocations", i); yr_set_integer( yr_le32toh(section->PointerToLinenumbers), pe->object, "sections[%i].pointer_to_line_numbers", i); yr_set_integer( yr_le32toh(section->NumberOfRelocations), pe->object, "sections[%i].number_of_relocations", i); yr_set_integer( yr_le32toh(section->NumberOfLinenumbers), pe->object, "sections[%i].number_of_line_numbers", i); // This will catch the section with the highest raw offset to help checking // if overlay data is present. If two sections have the same raw pointer // but different raw sizes the largest one is used. An example of this case // is file: cf62bf1815a93e68e6c5189f689286b66c4088b9507cf3ecf835e4ac3f9ededa section_end = yr_le32toh(section->PointerToRawData) + yr_le32toh(section->SizeOfRawData); if (section_end > highest_sec_ofs + highest_sec_siz) { highest_sec_ofs = yr_le32toh(section->PointerToRawData); highest_sec_siz = yr_le32toh(section->SizeOfRawData); } section++; } // An overlay is data appended to a PE file. Its location is at // RawData + RawOffset of the last section on the physical file last_section_end = highest_sec_siz + highest_sec_ofs; // For PE files that have overlaid data overlay.offset contains the offset // within the file where the overlay starts and overlay.size contains the // size. If the PE file doesn't have an overlay both fields are 0, if the // file is not a PE file (or is a malformed PE) both fields are YR_UNDEFINED. if (last_section_end && (pe->data_size > last_section_end)) { yr_set_integer(last_section_end, pe->object, "overlay.offset"); yr_set_integer( pe->data_size - last_section_end, pe->object, "overlay.size"); } else { yr_set_integer(0, pe->object, "overlay.offset"); yr_set_integer(0, pe->object, "overlay.size"); } } // // Given a posix timestamp argument, make sure not_before <= arg <= not_after // define_function(valid_on) { int64_t timestamp; int64_t not_before; int64_t not_after; if (yr_is_undefined(yr_parent(), "not_before") || yr_is_undefined(yr_parent(), "not_after")) { return_integer(YR_UNDEFINED); } timestamp = integer_argument(1); not_before = yr_get_integer(yr_parent(), "not_before"); not_after = yr_get_integer(yr_parent(), "not_after"); return_integer(timestamp >= not_before && timestamp <= not_after); } define_function(section_index_addr) { YR_OBJECT* module = yr_module(); YR_SCAN_CONTEXT* context = yr_scan_context(); int64_t offset; int64_t size; int64_t addr = integer_argument(1); int64_t n = yr_get_integer(module, "number_of_sections"); if (yr_is_undefined(module, "number_of_sections")) return_integer(YR_UNDEFINED); for (int i = 0; i < yr_min(n, MAX_PE_SECTIONS); i++) { if (context->flags & SCAN_FLAGS_PROCESS_MEMORY) { offset = yr_get_integer(module, "sections[%i].virtual_address", i); size = yr_get_integer(module, "sections[%i].virtual_size", i); } else { offset = yr_get_integer(module, "sections[%i].raw_data_offset", i); size = yr_get_integer(module, "sections[%i].raw_data_size", i); } if (addr >= offset && addr < offset + size) return_integer(i); } return_integer(YR_UNDEFINED); } define_function(section_index_name) { YR_OBJECT* module = yr_module(); char* name = string_argument(1); int64_t n = yr_get_integer(module, "number_of_sections"); if (yr_is_undefined(module, "number_of_sections")) return_integer(YR_UNDEFINED); for (int i = 0; i < yr_min(n, MAX_PE_SECTIONS); i++) { SIZED_STRING* sect = yr_get_string(module, "sections[%i].name", i); if (sect != NULL && strcmp(name, sect->c_string) == 0) return_integer(i); } return_integer(YR_UNDEFINED); } define_function(exports) { SIZED_STRING* search_name = sized_string_argument(1); SIZED_STRING* function_name = NULL; YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; // If not a PE, return YR_UNDEFINED. if (pe == NULL) return_integer(YR_UNDEFINED); // If PE, but no exported functions, return false. int n = (int) yr_get_integer(module, "number_of_exports"); if (n == 0) return_integer(0); for (int i = 0; i < n; i++) { function_name = yr_get_string(module, "export_details[%i].name", i); if (function_name == NULL) continue; if (ss_icompare(function_name, search_name) == 0) return_integer(1); } return_integer(0); } define_function(exports_regexp) { RE* regex = regexp_argument(1); SIZED_STRING* function_name = NULL; YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; // If not a PE, return YR_UNDEFINED. if (pe == NULL) return_integer(YR_UNDEFINED); // If PE, but no exported functions, return false. int n = (int) yr_get_integer(module, "number_of_exports"); if (n == 0) return_integer(0); for (int i = 0; i < n; i++) { function_name = yr_get_string(module, "export_details[%i].name", i); if (function_name == NULL) continue; if (yr_re_match(yr_scan_context(), regex, function_name->c_string) != -1) return_integer(1); } return_integer(0); } define_function(exports_ordinal) { int64_t ordinal = integer_argument(1); YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; // If not a PE, return YR_UNDEFINED. if (pe == NULL) return_integer(YR_UNDEFINED); // If PE, but no exported functions, return false. int n = (int) yr_get_integer(module, "number_of_exports"); if (n == 0) return_integer(0); if (ordinal == 0 || ordinal > n) return_integer(0); for (int i = 0; i < n; i++) { int64_t exported_ordinal = yr_object_get_integer( module, "export_details[%i].ordinal", i); if (exported_ordinal == ordinal) return_integer(1); } return_integer(0); } define_function(exports_index_name) { SIZED_STRING* search_name = sized_string_argument(1); SIZED_STRING* function_name = NULL; YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; // If not a PE, return YR_UNDEFINED. if (pe == NULL) return_integer(YR_UNDEFINED); // If PE, but no exported functions, return false. int n = (int) yr_get_integer(module, "number_of_exports"); if (n == 0) return_integer(YR_UNDEFINED); for (int i = 0; i < n; i++) { function_name = yr_get_string(module, "export_details[%i].name", i); if (function_name == NULL) continue; if (ss_icompare(function_name, search_name) == 0) return_integer(i); } return_integer(YR_UNDEFINED); } define_function(exports_index_ordinal) { int64_t ordinal = integer_argument(1); YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; // If not a PE, return YR_UNDEFINED. if (pe == NULL) return_integer(YR_UNDEFINED); // If PE, but no exported functions, return false. int n = (int) yr_get_integer(module, "number_of_exports"); if (n == 0) return_integer(YR_UNDEFINED); if (ordinal == 0 || ordinal > n) return_integer(YR_UNDEFINED); for (int i = 0; i < n; i++) { int64_t exported_ordinal = yr_object_get_integer( module, "export_details[%i].ordinal", i); if (exported_ordinal == ordinal) return_integer(i); } return_integer(YR_UNDEFINED); } define_function(exports_index_regex) { RE* regex = regexp_argument(1); SIZED_STRING* function_name = NULL; YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; // If not a PE, return YR_UNDEFINED. if (pe == NULL) return_integer(YR_UNDEFINED); // If PE, but no exported functions, return false. int n = (int) yr_get_integer(module, "number_of_exports"); if (n == 0) return_integer(YR_UNDEFINED); for (int i = 0; i < n; i++) { function_name = yr_get_string(module, "export_details[%i].name", i); if (function_name == NULL) continue; if (yr_re_match(yr_scan_context(), regex, function_name->c_string) != -1) { return_integer(i); } } return_integer(YR_UNDEFINED); } #if defined(HAVE_LIBCRYPTO) || defined(HAVE_WINCRYPT_H) || \ defined(HAVE_COMMONCRYPTO_COMMONCRYPTO_H) // // Generate an import hash: // https://www.mandiant.com/blog/tracking-malware-import-hashing/ // It is important to make duplicates of the strings as we don't want // to alter the contents of the parsed import structures. // define_function(imphash) { YR_OBJECT* module = yr_module(); IMPORTED_DLL* dll; yr_md5_ctx ctx; unsigned char digest[YR_MD5_LEN]; char* digest_ascii; size_t i; bool first = true; PE* pe = (PE*) module->data; // If not a PE, return YR_UNDEFINED. if (!pe) return_string(YR_UNDEFINED); // Lookup in cache first. digest_ascii = (char*) yr_hash_table_lookup(pe->hash_table, "imphash", NULL); if (digest_ascii != NULL) return_string(digest_ascii); yr_md5_init(&ctx); dll = pe->imported_dlls; while (dll) { IMPORT_FUNCTION* func; size_t dll_name_len; char* dll_name; // If extension is 'ocx', 'sys' or 'dll', chop it. char* ext = strrchr(dll->name, '.'); if (ext && (strncasecmp(ext, ".ocx", 4) == 0 || strncasecmp(ext, ".sys", 4) == 0 || strncasecmp(ext, ".dll", 4) == 0)) { dll_name_len = (ext - dll->name); } else { dll_name_len = strlen(dll->name); } // Allocate a new string to hold the dll name. dll_name = (char*) yr_malloc(dll_name_len + 1); if (!dll_name) return ERROR_INSUFFICIENT_MEMORY; strlcpy(dll_name, dll->name, dll_name_len + 1); func = dll->functions; while (func) { char* final_name; size_t final_name_len = dll_name_len + strlen(func->name) + 1; if (!first) final_name_len++; // Additional byte to accommodate the extra comma final_name = (char*) yr_malloc(final_name_len + 1); if (final_name == NULL) break; sprintf(final_name, first ? "%s.%s" : ",%s.%s", dll_name, func->name); // Lowercase the whole thing. for (i = 0; i < final_name_len; i++) final_name[i] = tolower(final_name[i]); yr_md5_update(&ctx, final_name, final_name_len); yr_free(final_name); func = func->next; first = false; } yr_free(dll_name); dll = dll->next; } yr_md5_final(digest, &ctx); digest_ascii = (char*) yr_malloc(YR_MD5_LEN * 2 + 1); if (digest_ascii == NULL) return ERROR_INSUFFICIENT_MEMORY; // Transform the binary digest to ascii for (i = 0; i < YR_MD5_LEN; i++) { sprintf(digest_ascii + (i * 2), "%02x", digest[i]); } digest_ascii[YR_MD5_LEN * 2] = '\0'; yr_hash_table_add(pe->hash_table, "imphash", NULL, digest_ascii); return_string(digest_ascii); } #endif // defined(HAVE_LIBCRYPTO) || defined(HAVE_WINCRYPT_H) int64_t pe_imports_dll(IMPORTED_DLL* dll, char* dll_name) { if (dll == NULL) return 0; int64_t result = 0; for (; dll != NULL; dll = dll->next) { if (strcasecmp(dll->name, dll_name) == 0) { IMPORT_FUNCTION* fun = dll->functions; for (; fun != NULL; fun = fun->next) { result++; } } } return result; } int64_t pe_imports(IMPORTED_DLL* dll, char* dll_name, char* fun_name) { if (dll == NULL) return 0; for (; dll != NULL; dll = dll->next) { if (strcasecmp(dll->name, dll_name) == 0) { IMPORT_FUNCTION* fun = dll->functions; for (; fun != NULL; fun = fun->next) { if (strcasecmp(fun->name, fun_name) == 0) return 1; } } } return 0; } int64_t pe_imports_regexp( YR_SCAN_CONTEXT* context, IMPORTED_DLL* dll, RE* dll_name, RE* fun_name) { if (dll == NULL) return 0; int64_t result = 0; for (; dll != NULL; dll = dll->next) { if (yr_re_match(context, dll_name, dll->name) > 0) { IMPORT_FUNCTION* fun = dll->functions; for (; fun != NULL; fun = fun->next) { if (yr_re_match(context, fun_name, fun->name) > 0) result++; } } } return result; } int64_t pe_imports_ordinal(IMPORTED_DLL* dll, char* dll_name, uint64_t ordinal) { if (dll == NULL) return 0; for (; dll != NULL; dll = dll->next) { if (strcasecmp(dll->name, dll_name) == 0) { IMPORT_FUNCTION* fun = dll->functions; for (; fun != NULL; fun = fun->next) { if (fun->has_ordinal && fun->ordinal == ordinal) return 1; } } } return 0; } define_function(imports_standard) { char* dll_name = string_argument(1); char* function_name = string_argument(2); YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; if (!pe) return_integer(YR_UNDEFINED); return_integer(pe_imports(pe->imported_dlls, dll_name, function_name)); } define_function(imports) { int64_t flags = integer_argument(1); char* dll_name = string_argument(2); char* function_name = string_argument(3); YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; if (!pe) return_integer(YR_UNDEFINED); if (flags & IMPORT_STANDARD && pe_imports(pe->imported_dlls, dll_name, function_name)) { return_integer(1); } if (flags & IMPORT_DELAYED && pe_imports(pe->delay_imported_dlls, dll_name, function_name)) { return_integer(1); } return_integer(0); } define_function(imports_standard_ordinal) { char* dll_name = string_argument(1); int64_t ordinal = integer_argument(2); YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; if (!pe) return_integer(YR_UNDEFINED); return_integer(pe_imports_ordinal(pe->imported_dlls, dll_name, ordinal)) } define_function(imports_ordinal) { int64_t flags = integer_argument(1); char* dll_name = string_argument(2); int64_t ordinal = integer_argument(3); YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; if (!pe) return_integer(YR_UNDEFINED); if (flags & IMPORT_STANDARD && pe_imports_ordinal(pe->imported_dlls, dll_name, ordinal)) { return_integer(1); } if (flags & IMPORT_DELAYED && pe_imports_ordinal(pe->delay_imported_dlls, dll_name, ordinal)) { return_integer(1); } return_integer(0); } define_function(imports_standard_regex) { RE* dll_name = regexp_argument(1); RE* function_name = regexp_argument(2); YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; if (!pe) return_integer(YR_UNDEFINED); return_integer(pe_imports_regexp( yr_scan_context(), pe->imported_dlls, dll_name, function_name)) } define_function(imports_regex) { int64_t flags = integer_argument(1); RE* dll_name = regexp_argument(2); RE* function_name = regexp_argument(3); YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; if (!pe) return_integer(YR_UNDEFINED); int64_t result = 0; if (flags & IMPORT_STANDARD) result += pe_imports_regexp( yr_scan_context(), pe->imported_dlls, dll_name, function_name); if (flags & IMPORT_DELAYED) result += pe_imports_regexp( yr_scan_context(), pe->delay_imported_dlls, dll_name, function_name); return_integer(result); } define_function(imports_standard_dll) { char* dll_name = string_argument(1); YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; if (!pe) return_integer(YR_UNDEFINED); return_integer(pe_imports_dll(pe->imported_dlls, dll_name)); } define_function(imports_dll) { int64_t flags = integer_argument(1); char* dll_name = string_argument(2); YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; if (!pe) return_integer(YR_UNDEFINED); int64_t result = 0; if (flags & IMPORT_STANDARD) result += pe_imports_dll(pe->imported_dlls, dll_name); if (flags & IMPORT_DELAYED) result += pe_imports_dll(pe->delay_imported_dlls, dll_name); return_integer(result); } define_function(import_rva) { SIZED_STRING* in_dll_name = sized_string_argument(1); SIZED_STRING* in_function_name = sized_string_argument(2); SIZED_STRING* dll_name; SIZED_STRING* function_name; YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; if (!pe) return_integer(YR_UNDEFINED); int64_t num_imports = yr_get_integer(pe->object, "number_of_imports"); if (IS_UNDEFINED(num_imports)) return_integer(YR_UNDEFINED); for (int i = 0; i < num_imports; i++) { dll_name = yr_get_string(module, "import_details[%i].library_name", i); if (dll_name == NULL || IS_UNDEFINED(dll_name) || ss_icompare(in_dll_name, dll_name) != 0) continue; int64_t num_functions = yr_get_integer( module, "import_details[%i].number_of_functions", i); if (IS_UNDEFINED(num_functions)) return_integer(YR_UNDEFINED); for (int j = 0; j < num_functions; j++) { function_name = yr_get_string( module, "import_details[%i].functions[%i].name", i, j); if (function_name == NULL || IS_UNDEFINED(function_name)) continue; if (ss_icompare(in_function_name, function_name) == 0) return_integer(yr_get_integer( module, "import_details[%i].functions[%i].rva", i, j)); } } return_integer(YR_UNDEFINED); } define_function(import_rva_ordinal) { SIZED_STRING* in_dll_name = sized_string_argument(1); int64_t in_ordinal = integer_argument(2); SIZED_STRING* dll_name; int64_t ordinal; YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; if (!pe) return_integer(YR_UNDEFINED); int64_t num_imports = yr_get_integer(pe->object, "number_of_imports"); if (IS_UNDEFINED(num_imports)) return_integer(YR_UNDEFINED); for (int i = 0; i < num_imports; i++) { dll_name = yr_get_string(module, "import_details[%i].library_name", i); if (dll_name == NULL || IS_UNDEFINED(dll_name) || ss_icompare(in_dll_name, dll_name) != 0) continue; int64_t num_functions = yr_get_integer( module, "import_details[%i].number_of_functions", i); if (IS_UNDEFINED(num_functions)) return_integer(YR_UNDEFINED); for (int j = 0; j < num_functions; j++) { ordinal = yr_get_integer( module, "import_details[%i].functions[%i].ordinal", i, j); if (IS_UNDEFINED(ordinal)) continue; if (ordinal == in_ordinal) return_integer(yr_get_integer( module, "import_details[%i].functions[%i].rva", i, j)); } } return_integer(YR_UNDEFINED); } define_function(delayed_import_rva) { SIZED_STRING* in_dll_name = sized_string_argument(1); SIZED_STRING* in_function_name = sized_string_argument(2); SIZED_STRING* dll_name; SIZED_STRING* function_name; YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; if (!pe) return_integer(YR_UNDEFINED); int64_t num_imports = yr_get_integer(pe->object, "number_of_delayed_imports"); if (IS_UNDEFINED(num_imports)) return_integer(YR_UNDEFINED); for (int i = 0; i < num_imports; i++) { dll_name = yr_get_string( module, "delayed_import_details[%i].library_name", i); if (dll_name == NULL || IS_UNDEFINED(dll_name) || ss_icompare(in_dll_name, dll_name) != 0) continue; int64_t num_functions = yr_get_integer( module, "delayed_import_details[%i].number_of_functions", i); if (IS_UNDEFINED(num_functions)) return_integer(YR_UNDEFINED); for (int j = 0; j < num_functions; j++) { function_name = yr_get_string( module, "delayed_import_details[%i].functions[%i].name", i, j); if (function_name == NULL || IS_UNDEFINED(function_name)) continue; if (ss_icompare(in_function_name, function_name) == 0) return_integer(yr_get_integer( module, "delayed_import_details[%i].functions[%i].rva", i, j)); } } return_integer(YR_UNDEFINED); } define_function(delayed_import_rva_ordinal) { SIZED_STRING* in_dll_name = sized_string_argument(1); int64_t in_ordinal = integer_argument(2); SIZED_STRING* dll_name; int64_t ordinal; YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; if (!pe) return_integer(YR_UNDEFINED); int64_t num_imports = yr_get_integer(pe->object, "number_of_delayed_imports"); if (IS_UNDEFINED(num_imports)) return_integer(YR_UNDEFINED); for (int i = 0; i < num_imports; i++) { dll_name = yr_get_string( module, "delayed_import_details[%i].library_name", i); if (dll_name == NULL || IS_UNDEFINED(dll_name) || ss_icompare(in_dll_name, dll_name) != 0) continue; int64_t num_functions = yr_get_integer( module, "delayed_import_details[%i].number_of_functions", i); if (IS_UNDEFINED(num_functions)) return_integer(YR_UNDEFINED); for (int j = 0; j < num_functions; j++) { ordinal = yr_get_integer( module, "delayed_import_details[%i].functions[%i].ordinal", i, j); if (IS_UNDEFINED(ordinal)) continue; if (ordinal == in_ordinal) return_integer(yr_get_integer( module, "delayed_import_details[%i].functions[%i].rva", i, j)); } } return_integer(YR_UNDEFINED); } define_function(locale) { YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; uint64_t locale = integer_argument(1); if (yr_is_undefined(module, "number_of_resources")) return_integer(YR_UNDEFINED); // If not a PE file, return YR_UNDEFINED if (pe == NULL) return_integer(YR_UNDEFINED); int n = (int) yr_get_integer(module, "number_of_resources"); for (int i = 0; i < n; i++) { uint64_t rsrc_language = yr_get_integer( module, "resources[%i].language", i); if ((rsrc_language & 0xFFFF) == locale) return_integer(1); } return_integer(0); } define_function(language) { YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; uint64_t language = integer_argument(1); if (yr_is_undefined(module, "number_of_resources")) return_integer(YR_UNDEFINED); // If not a PE file, return YR_UNDEFINED if (pe == NULL) return_integer(YR_UNDEFINED); int n = (int) yr_get_integer(module, "number_of_resources"); for (int i = 0; i < n; i++) { uint64_t rsrc_language = yr_get_integer( module, "resources[%i].language", i); if ((rsrc_language & 0xFF) == language) return_integer(1); } return_integer(0); } define_function(is_dll) { int64_t characteristics; YR_OBJECT* module = yr_module(); if (yr_is_undefined(module, "characteristics")) return_integer(YR_UNDEFINED); characteristics = yr_get_integer(module, "characteristics"); return_integer(characteristics & IMAGE_FILE_DLL); } define_function(is_32bit) { YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; if (pe == NULL) return_integer(YR_UNDEFINED); return_integer(IS_64BITS_PE(pe) ? 0 : 1); } define_function(is_64bit) { YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; if (pe == NULL) return_integer(YR_UNDEFINED); return_integer(IS_64BITS_PE(pe) ? 1 : 0); } // _rich_version // // Returns the number of rich signatures that match the specified version and // toolid numbers. // static int64_t _rich_version( YR_OBJECT* module, uint64_t version, uint64_t toolid) { int64_t rich_length; int64_t rich_count; PRICH_SIGNATURE clear_rich_signature; SIZED_STRING* rich_string; int64_t result = 0; // Check if the required fields are set if (yr_is_undefined(module, "rich_signature.length")) return YR_UNDEFINED; rich_length = yr_get_integer(module, "rich_signature.length"); rich_string = yr_get_string(module, "rich_signature.clear_data"); // If clear_data was not set, return YR_UNDEFINED if (rich_string == NULL) return YR_UNDEFINED; // File e77b007c9a964411c5e33afeec18be32c86963b78f3c3e906b28fcf1382f46c3 // has a Rich header of length 8, which is smaller than RICH_SIGNATURE and // causes a crash. if (rich_length < sizeof(RICH_SIGNATURE)) return YR_UNDEFINED; if (version == YR_UNDEFINED && toolid == YR_UNDEFINED) return 0; clear_rich_signature = (PRICH_SIGNATURE) rich_string->c_string; // Loop over the versions in the rich signature rich_count = (rich_length - sizeof(RICH_SIGNATURE)) / sizeof(RICH_VERSION_INFO); for (int i = 0; i < rich_count; i++) { DWORD id_version = yr_le32toh(clear_rich_signature->versions[i].id_version); int match_version = (version == RICH_VERSION_VERSION(id_version)); int match_toolid = (toolid == RICH_VERSION_ID(id_version)); if ((version == YR_UNDEFINED || match_version) && (toolid == YR_UNDEFINED || match_toolid)) { result += yr_le32toh(clear_rich_signature->versions[i].times); } } return result; } define_function(rich_version) { return_integer(_rich_version(yr_module(), integer_argument(1), YR_UNDEFINED)); } define_function(rich_version_toolid) { return_integer( _rich_version(yr_module(), integer_argument(1), integer_argument(2))); } define_function(rich_toolid) { return_integer(_rich_version(yr_module(), YR_UNDEFINED, integer_argument(1))); } define_function(rich_toolid_version) { return_integer( _rich_version(yr_module(), integer_argument(2), integer_argument(1))); } define_function(calculate_checksum) { YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; uint64_t csum = 0; size_t csum_offset; if (pe == NULL) return_integer(YR_UNDEFINED); csum_offset = ((uint8_t*) &(pe->header->OptionalHeader) + offsetof(IMAGE_OPTIONAL_HEADER32, CheckSum)) - pe->data; for (size_t i = 0; i <= pe->data_size / 4; i++) { // Treat the CheckSum field as 0 -- the offset is the same for // PE32 and PE64. if (4 * i == csum_offset) continue; if (4 * i + 4 <= pe->data_size) { csum += ((uint64_t) pe->data[4 * i] + ((uint64_t) pe->data[4 * i + 1] << 8) + ((uint64_t) pe->data[4 * i + 2] << 16) + ((uint64_t) pe->data[4 * i + 3] << 24)); } else { for (size_t j = 0; j < pe->data_size % 4; j++) csum += (uint64_t) pe->data[4 * i + j] << (8 * j); } if (csum > 0xffffffff) csum = (csum & 0xffffffff) + (csum >> 32); } csum = (csum & 0xffff) + (csum >> 16); csum += (csum >> 16); csum &= 0xffff; csum += pe->data_size; return_integer(csum); } define_function(rva_to_offset) { YR_OBJECT* module = yr_module(); PE* pe = (PE*) module->data; uint64_t rva; int64_t offset; if (pe == NULL) return_integer(YR_UNDEFINED); rva = integer_argument(1); offset = pe_rva_to_offset(pe, rva); if (offset == -1) return_integer(YR_UNDEFINED); return_integer(offset); } begin_declarations declare_integer("MACHINE_UNKNOWN"); declare_integer("MACHINE_AM33"); declare_integer("MACHINE_AMD64"); declare_integer("MACHINE_ARM"); declare_integer("MACHINE_ARMNT"); declare_integer("MACHINE_ARM64"); declare_integer("MACHINE_EBC"); declare_integer("MACHINE_I386"); declare_integer("MACHINE_IA64"); declare_integer("MACHINE_M32R"); declare_integer("MACHINE_MIPS16"); declare_integer("MACHINE_MIPSFPU"); declare_integer("MACHINE_MIPSFPU16"); declare_integer("MACHINE_POWERPC"); declare_integer("MACHINE_POWERPCFP"); declare_integer("MACHINE_R4000"); declare_integer("MACHINE_SH3"); declare_integer("MACHINE_SH3DSP"); declare_integer("MACHINE_SH4"); declare_integer("MACHINE_SH5"); declare_integer("MACHINE_THUMB"); declare_integer("MACHINE_WCEMIPSV2"); declare_integer("MACHINE_TARGET_HOST"); declare_integer("MACHINE_R3000"); declare_integer("MACHINE_R10000"); declare_integer("MACHINE_ALPHA"); declare_integer("MACHINE_SH3E"); declare_integer("MACHINE_ALPHA64"); declare_integer("MACHINE_AXP64"); declare_integer("MACHINE_TRICORE"); declare_integer("MACHINE_CEF"); declare_integer("MACHINE_CEE"); declare_integer("SUBSYSTEM_UNKNOWN"); declare_integer("SUBSYSTEM_NATIVE"); declare_integer("SUBSYSTEM_WINDOWS_GUI"); declare_integer("SUBSYSTEM_WINDOWS_CUI"); declare_integer("SUBSYSTEM_OS2_CUI"); declare_integer("SUBSYSTEM_POSIX_CUI"); declare_integer("SUBSYSTEM_NATIVE_WINDOWS"); declare_integer("SUBSYSTEM_WINDOWS_CE_GUI"); declare_integer("SUBSYSTEM_EFI_APPLICATION"); declare_integer("SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER"); declare_integer("SUBSYSTEM_EFI_RUNTIME_DRIVER"); declare_integer("SUBSYSTEM_EFI_ROM_IMAGE"); declare_integer("SUBSYSTEM_XBOX"); declare_integer("SUBSYSTEM_WINDOWS_BOOT_APPLICATION"); declare_integer("HIGH_ENTROPY_VA"); declare_integer("DYNAMIC_BASE"); declare_integer("FORCE_INTEGRITY"); declare_integer("NX_COMPAT"); declare_integer("NO_ISOLATION"); declare_integer("NO_SEH"); declare_integer("NO_BIND"); declare_integer("APPCONTAINER"); declare_integer("WDM_DRIVER"); declare_integer("GUARD_CF"); declare_integer("TERMINAL_SERVER_AWARE"); declare_integer("RELOCS_STRIPPED"); declare_integer("EXECUTABLE_IMAGE"); declare_integer("LINE_NUMS_STRIPPED"); declare_integer("LOCAL_SYMS_STRIPPED"); declare_integer("AGGRESIVE_WS_TRIM"); declare_integer("LARGE_ADDRESS_AWARE"); declare_integer("BYTES_REVERSED_LO"); declare_integer("MACHINE_32BIT"); declare_integer("DEBUG_STRIPPED"); declare_integer("REMOVABLE_RUN_FROM_SWAP"); declare_integer("NET_RUN_FROM_SWAP"); declare_integer("SYSTEM"); declare_integer("DLL"); declare_integer("UP_SYSTEM_ONLY"); declare_integer("BYTES_REVERSED_HI"); declare_integer("IMAGE_DIRECTORY_ENTRY_EXPORT"); declare_integer("IMAGE_DIRECTORY_ENTRY_IMPORT"); declare_integer("IMAGE_DIRECTORY_ENTRY_RESOURCE"); declare_integer("IMAGE_DIRECTORY_ENTRY_EXCEPTION"); declare_integer("IMAGE_DIRECTORY_ENTRY_SECURITY"); declare_integer("IMAGE_DIRECTORY_ENTRY_BASERELOC"); declare_integer("IMAGE_DIRECTORY_ENTRY_DEBUG"); declare_integer("IMAGE_DIRECTORY_ENTRY_ARCHITECTURE"); declare_integer("IMAGE_DIRECTORY_ENTRY_COPYRIGHT"); declare_integer("IMAGE_DIRECTORY_ENTRY_GLOBALPTR"); declare_integer("IMAGE_DIRECTORY_ENTRY_TLS"); declare_integer("IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG"); declare_integer("IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT"); declare_integer("IMAGE_DIRECTORY_ENTRY_IAT"); declare_integer("IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT"); declare_integer("IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR"); declare_integer("IMAGE_NT_OPTIONAL_HDR32_MAGIC"); declare_integer("IMAGE_NT_OPTIONAL_HDR64_MAGIC"); declare_integer("IMAGE_ROM_OPTIONAL_HDR_MAGIC"); declare_integer("SECTION_NO_PAD"); declare_integer("SECTION_CNT_CODE"); declare_integer("SECTION_CNT_INITIALIZED_DATA"); declare_integer("SECTION_CNT_UNINITIALIZED_DATA"); declare_integer("SECTION_LNK_OTHER"); declare_integer("SECTION_LNK_INFO"); declare_integer("SECTION_LNK_REMOVE"); declare_integer("SECTION_LNK_COMDAT"); declare_integer("SECTION_NO_DEFER_SPEC_EXC"); declare_integer("SECTION_GPREL"); declare_integer("SECTION_MEM_FARDATA"); declare_integer("SECTION_MEM_PURGEABLE"); declare_integer("SECTION_MEM_16BIT"); declare_integer("SECTION_MEM_LOCKED"); declare_integer("SECTION_MEM_PRELOAD"); declare_integer("SECTION_ALIGN_1BYTES"); declare_integer("SECTION_ALIGN_2BYTES"); declare_integer("SECTION_ALIGN_4BYTES"); declare_integer("SECTION_ALIGN_8BYTES"); declare_integer("SECTION_ALIGN_16BYTES"); declare_integer("SECTION_ALIGN_32BYTES"); declare_integer("SECTION_ALIGN_64BYTES"); declare_integer("SECTION_ALIGN_128BYTES"); declare_integer("SECTION_ALIGN_256BYTES"); declare_integer("SECTION_ALIGN_512BYTES"); declare_integer("SECTION_ALIGN_1024BYTES"); declare_integer("SECTION_ALIGN_2048BYTES"); declare_integer("SECTION_ALIGN_4096BYTES"); declare_integer("SECTION_ALIGN_8192BYTES"); declare_integer("SECTION_ALIGN_MASK"); declare_integer("SECTION_LNK_NRELOC_OVFL"); declare_integer("SECTION_MEM_DISCARDABLE"); declare_integer("SECTION_MEM_NOT_CACHED"); declare_integer("SECTION_MEM_NOT_PAGED"); declare_integer("SECTION_MEM_SHARED"); declare_integer("SECTION_MEM_EXECUTE"); declare_integer("SECTION_MEM_READ"); declare_integer("SECTION_MEM_WRITE"); declare_integer("SECTION_SCALE_INDEX"); declare_integer("RESOURCE_TYPE_CURSOR"); declare_integer("RESOURCE_TYPE_BITMAP"); declare_integer("RESOURCE_TYPE_ICON"); declare_integer("RESOURCE_TYPE_MENU"); declare_integer("RESOURCE_TYPE_DIALOG"); declare_integer("RESOURCE_TYPE_STRING"); declare_integer("RESOURCE_TYPE_FONTDIR"); declare_integer("RESOURCE_TYPE_FONT"); declare_integer("RESOURCE_TYPE_ACCELERATOR"); declare_integer("RESOURCE_TYPE_RCDATA"); declare_integer("RESOURCE_TYPE_MESSAGETABLE"); declare_integer("RESOURCE_TYPE_GROUP_CURSOR"); declare_integer("RESOURCE_TYPE_GROUP_ICON"); declare_integer("RESOURCE_TYPE_VERSION"); declare_integer("RESOURCE_TYPE_DLGINCLUDE"); declare_integer("RESOURCE_TYPE_PLUGPLAY"); declare_integer("RESOURCE_TYPE_VXD"); declare_integer("RESOURCE_TYPE_ANICURSOR"); declare_integer("RESOURCE_TYPE_ANIICON"); declare_integer("RESOURCE_TYPE_HTML"); declare_integer("RESOURCE_TYPE_MANIFEST"); declare_integer("IMAGE_DEBUG_TYPE_UNKNOWN"); declare_integer("IMAGE_DEBUG_TYPE_COFF"); declare_integer("IMAGE_DEBUG_TYPE_CODEVIEW"); declare_integer("IMAGE_DEBUG_TYPE_FPO"); declare_integer("IMAGE_DEBUG_TYPE_MISC"); declare_integer("IMAGE_DEBUG_TYPE_EXCEPTION"); declare_integer("IMAGE_DEBUG_TYPE_FIXUP"); declare_integer("IMAGE_DEBUG_TYPE_OMAP_TO_SRC"); declare_integer("IMAGE_DEBUG_TYPE_OMAP_FROM_SRC"); declare_integer("IMAGE_DEBUG_TYPE_BORLAND"); declare_integer("IMAGE_DEBUG_TYPE_RESERVED10"); declare_integer("IMAGE_DEBUG_TYPE_CLSID"); declare_integer("IMAGE_DEBUG_TYPE_VC_FEATURE"); declare_integer("IMAGE_DEBUG_TYPE_POGO"); declare_integer("IMAGE_DEBUG_TYPE_ILTCG"); declare_integer("IMAGE_DEBUG_TYPE_MPX"); declare_integer("IMAGE_DEBUG_TYPE_REPRO"); declare_integer("IMPORT_DELAYED"); declare_integer("IMPORT_STANDARD"); declare_integer("IMPORT_ANY"); declare_integer("is_pe"); declare_integer("machine"); declare_integer("number_of_sections"); declare_integer("timestamp"); declare_integer("pointer_to_symbol_table"); declare_integer("number_of_symbols"); declare_integer("size_of_optional_header"); declare_integer("characteristics"); declare_integer("entry_point"); declare_integer("entry_point_raw"); declare_integer("image_base"); declare_integer("number_of_rva_and_sizes"); declare_integer("number_of_version_infos"); declare_string_dictionary("version_info"); begin_struct_array("version_info_list") declare_string("key"); declare_string("value"); end_struct_array("version_info_list"); declare_integer("opthdr_magic"); declare_integer("size_of_code"); declare_integer("size_of_initialized_data"); declare_integer("size_of_uninitialized_data"); declare_integer("base_of_code"); declare_integer("base_of_data"); declare_integer("section_alignment"); declare_integer("file_alignment"); begin_struct("linker_version") declare_integer("major"); declare_integer("minor"); end_struct("linker_version"); begin_struct("os_version") declare_integer("major"); declare_integer("minor"); end_struct("os_version"); begin_struct("image_version") declare_integer("major"); declare_integer("minor"); end_struct("image_version"); begin_struct("subsystem_version") declare_integer("major"); declare_integer("minor"); end_struct("subsystem_version"); declare_integer("win32_version_value"); declare_integer("size_of_image"); declare_integer("size_of_headers"); declare_integer("checksum"); declare_function("calculate_checksum", "", "i", calculate_checksum); declare_integer("subsystem"); declare_integer("dll_characteristics"); declare_integer("size_of_stack_reserve"); declare_integer("size_of_stack_commit"); declare_integer("size_of_heap_reserve"); declare_integer("size_of_heap_commit"); declare_integer("loader_flags"); begin_struct_array("data_directories") declare_integer("virtual_address"); declare_integer("size"); end_struct_array("data_directories"); begin_struct_array("sections") declare_string("name"); declare_string("full_name"); declare_integer("characteristics"); declare_integer("virtual_address"); declare_integer("virtual_size"); declare_integer("raw_data_offset"); declare_integer("raw_data_size"); declare_integer("pointer_to_relocations"); declare_integer("pointer_to_line_numbers"); declare_integer("number_of_relocations"); declare_integer("number_of_line_numbers"); end_struct_array("sections"); begin_struct("overlay") declare_integer("offset"); declare_integer("size"); end_struct("overlay"); begin_struct("rich_signature") declare_integer("offset"); declare_integer("length"); declare_integer("key"); declare_string("raw_data"); declare_string("clear_data"); declare_string("version_data"); declare_function("version", "i", "i", rich_version); declare_function("version", "ii", "i", rich_version_toolid); declare_function("toolid", "i", "i", rich_toolid); declare_function("toolid", "ii", "i", rich_toolid_version); end_struct("rich_signature"); #if defined(HAVE_LIBCRYPTO) || defined(HAVE_WINCRYPT_H) || \ defined(HAVE_COMMONCRYPTO_COMMONCRYPTO_H) declare_function("imphash", "", "s", imphash); #endif declare_function("section_index", "s", "i", section_index_name); declare_function("section_index", "i", "i", section_index_addr); declare_function("exports", "s", "i", exports); declare_function("exports", "r", "i", exports_regexp); declare_function("exports", "i", "i", exports_ordinal); declare_function("exports_index", "s", "i", exports_index_name); declare_function("exports_index", "i", "i", exports_index_ordinal); declare_function("exports_index", "r", "i", exports_index_regex); declare_function("imports", "ss", "i", imports_standard); declare_function("imports", "si", "i", imports_standard_ordinal); declare_function("imports", "s", "i", imports_standard_dll); declare_function("imports", "rr", "i", imports_standard_regex); declare_function("imports", "iss", "i", imports); declare_function("imports", "isi", "i", imports_ordinal); declare_function("imports", "is", "i", imports_dll); declare_function("imports", "irr", "i", imports_regex); declare_function("import_rva", "ss", "i", import_rva); declare_function("import_rva", "si", "i", import_rva_ordinal); declare_function("delayed_import_rva", "ss", "i", delayed_import_rva); declare_function("delayed_import_rva", "si", "i", delayed_import_rva_ordinal); declare_function("locale", "i", "i", locale); declare_function("language", "i", "i", language); declare_function("is_dll", "", "i", is_dll); declare_function("is_32bit", "", "i", is_32bit); declare_function("is_64bit", "", "i", is_64bit); declare_integer("number_of_imports"); declare_integer("number_of_imported_functions"); declare_integer("number_of_delayed_imports"); declare_integer("number_of_delayed_imported_functions"); declare_integer("number_of_exports"); declare_string("dll_name"); declare_integer("export_timestamp"); begin_struct_array("export_details") declare_integer("offset"); declare_string("name"); declare_string("forward_name"); declare_integer("ordinal"); declare_integer("rva"); end_struct_array("export_details") begin_struct_array("import_details") declare_string("library_name"); declare_integer("number_of_functions"); begin_struct_array("functions") declare_string("name"); declare_integer("ordinal"); declare_integer("rva"); end_struct_array("functions"); end_struct_array("import_details"); begin_struct_array("delayed_import_details") declare_string("library_name"); declare_integer("number_of_functions"); begin_struct_array("functions") declare_string("name"); declare_integer("ordinal"); declare_integer("rva"); end_struct_array("functions"); end_struct_array("delayed_import_details"); declare_integer("resource_timestamp"); begin_struct("resource_version") declare_integer("major"); declare_integer("minor"); end_struct("resource_version") begin_struct_array("resources") declare_integer("rva"); declare_integer("offset"); declare_integer("length"); declare_integer("type"); declare_integer("id"); declare_integer("language"); declare_string("type_string"); declare_string("name_string"); declare_string("language_string"); end_struct_array("resources") declare_integer("number_of_resources"); declare_string("pdb_path"); #if defined(HAVE_LIBCRYPTO) && !defined(BORINGSSL) begin_struct_array("signatures") declare_string("thumbprint"); declare_string("issuer"); declare_string("subject"); declare_integer("version"); declare_string("algorithm"); declare_string("algorithm_oid"); declare_string("serial"); declare_integer("not_before"); declare_integer("not_after"); declare_integer("verified"); declare_string("digest_alg"); declare_string("digest"); declare_string("file_digest"); declare_integer("number_of_certificates"); begin_struct_array("certificates") ; declare_string("thumbprint"); declare_string("issuer"); declare_string("subject"); declare_integer("version"); declare_string("algorithm"); declare_string("algorithm_oid"); declare_string("serial"); declare_integer("not_before"); declare_integer("not_after"); end_struct_array("certificates"); begin_struct("signer_info") ; declare_string("program_name"); declare_string("digest"); declare_string("digest_alg"); declare_integer("length_of_chain"); begin_struct_array("chain") ; declare_string("thumbprint"); declare_string("issuer"); declare_string("subject"); declare_integer("version"); declare_string("algorithm"); declare_string("algorithm_oid"); declare_string("serial"); declare_integer("not_before"); declare_integer("not_after"); end_struct_array("chain"); end_struct("signer_info"); declare_integer("number_of_countersignatures"); begin_struct_array("countersignatures") ; declare_integer("verified"); declare_integer("sign_time"); declare_string("digest_alg"); declare_string("digest"); declare_integer("length_of_chain"); begin_struct_array("chain") ; declare_string("thumbprint"); declare_string("issuer"); declare_string("subject"); declare_integer("version"); declare_string("algorithm"); declare_string("algorithm_oid"); declare_string("serial"); declare_integer("not_before"); declare_integer("not_after"); end_struct_array("chain"); end_struct_array("countersignatures") declare_function("valid_on", "i", "i", valid_on); end_struct_array("signatures") // If any of the signatures correctly signs the binary declare_integer("is_signed"); declare_integer("number_of_signatures"); #endif declare_function("rva_to_offset", "i", "i", rva_to_offset); end_declarations int module_initialize(YR_MODULE* module) { #if defined(HAVE_LIBCRYPTO) && !defined(BORINGSSL) // Initialize OpenSSL global objects for the auth library before any // multithreaded environment as it is not thread-safe. This can // only be called once per process. static bool s_initialized = false; if (!s_initialized) { s_initialized = true; initialize_authenticode_parser(); } #endif return ERROR_SUCCESS; } int module_finalize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { YR_MEMORY_BLOCK* block; YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; PIMAGE_NT_HEADERS32 pe_header; const uint8_t* block_data = NULL; PE* pe = NULL; yr_set_integer(IMPORT_DELAYED, module_object, "IMPORT_DELAYED"); yr_set_integer(IMPORT_STANDARD, module_object, "IMPORT_STANDARD"); yr_set_integer(IMPORT_ANY, module_object, "IMPORT_ANY"); yr_set_integer(IMAGE_FILE_MACHINE_UNKNOWN, module_object, "MACHINE_UNKNOWN"); yr_set_integer(IMAGE_FILE_MACHINE_AM33, module_object, "MACHINE_AM33"); yr_set_integer(IMAGE_FILE_MACHINE_AMD64, module_object, "MACHINE_AMD64"); yr_set_integer(IMAGE_FILE_MACHINE_ARM, module_object, "MACHINE_ARM"); yr_set_integer(IMAGE_FILE_MACHINE_ARMNT, module_object, "MACHINE_ARMNT"); yr_set_integer(IMAGE_FILE_MACHINE_ARM64, module_object, "MACHINE_ARM64"); yr_set_integer(IMAGE_FILE_MACHINE_EBC, module_object, "MACHINE_EBC"); yr_set_integer(IMAGE_FILE_MACHINE_I386, module_object, "MACHINE_I386"); yr_set_integer(IMAGE_FILE_MACHINE_IA64, module_object, "MACHINE_IA64"); yr_set_integer(IMAGE_FILE_MACHINE_M32R, module_object, "MACHINE_M32R"); yr_set_integer(IMAGE_FILE_MACHINE_MIPS16, module_object, "MACHINE_MIPS16"); yr_set_integer(IMAGE_FILE_MACHINE_MIPSFPU, module_object, "MACHINE_MIPSFPU"); yr_set_integer( IMAGE_FILE_MACHINE_MIPSFPU16, module_object, "MACHINE_MIPSFPU16"); yr_set_integer(IMAGE_FILE_MACHINE_POWERPC, module_object, "MACHINE_POWERPC"); yr_set_integer( IMAGE_FILE_MACHINE_POWERPCFP, module_object, "MACHINE_POWERPCFP"); yr_set_integer(IMAGE_FILE_MACHINE_R4000, module_object, "MACHINE_R4000"); yr_set_integer(IMAGE_FILE_MACHINE_SH3, module_object, "MACHINE_SH3"); yr_set_integer(IMAGE_FILE_MACHINE_SH3DSP, module_object, "MACHINE_SH3DSP"); yr_set_integer(IMAGE_FILE_MACHINE_SH4, module_object, "MACHINE_SH4"); yr_set_integer(IMAGE_FILE_MACHINE_SH5, module_object, "MACHINE_SH5"); yr_set_integer(IMAGE_FILE_MACHINE_THUMB, module_object, "MACHINE_THUMB"); yr_set_integer( IMAGE_FILE_MACHINE_WCEMIPSV2, module_object, "MACHINE_WCEMIPSV2"); yr_set_integer( IMAGE_FILE_MACHINE_TARGET_HOST, module_object, "MACHINE_TARGET_HOST"); yr_set_integer(IMAGE_FILE_MACHINE_R3000, module_object, "MACHINE_R3000"); yr_set_integer(IMAGE_FILE_MACHINE_R10000, module_object, "MACHINE_R10000"); yr_set_integer(IMAGE_FILE_MACHINE_ALPHA, module_object, "MACHINE_ALPHA"); yr_set_integer(IMAGE_FILE_MACHINE_SH3E, module_object, "MACHINE_SH3E"); yr_set_integer(IMAGE_FILE_MACHINE_ALPHA64, module_object, "MACHINE_ALPHA64"); yr_set_integer(IMAGE_FILE_MACHINE_AXP64, module_object, "MACHINE_AXP64"); yr_set_integer(IMAGE_FILE_MACHINE_TRICORE, module_object, "MACHINE_TRICORE"); yr_set_integer(IMAGE_FILE_MACHINE_CEF, module_object, "MACHINE_CEF"); yr_set_integer(IMAGE_FILE_MACHINE_CEE, module_object, "MACHINE_CEE"); yr_set_integer(IMAGE_SUBSYSTEM_UNKNOWN, module_object, "SUBSYSTEM_UNKNOWN"); yr_set_integer(IMAGE_SUBSYSTEM_NATIVE, module_object, "SUBSYSTEM_NATIVE"); yr_set_integer( IMAGE_SUBSYSTEM_WINDOWS_GUI, module_object, "SUBSYSTEM_WINDOWS_GUI"); yr_set_integer( IMAGE_SUBSYSTEM_WINDOWS_CUI, module_object, "SUBSYSTEM_WINDOWS_CUI"); yr_set_integer(IMAGE_SUBSYSTEM_OS2_CUI, module_object, "SUBSYSTEM_OS2_CUI"); yr_set_integer( IMAGE_SUBSYSTEM_POSIX_CUI, module_object, "SUBSYSTEM_POSIX_CUI"); yr_set_integer( IMAGE_SUBSYSTEM_NATIVE_WINDOWS, module_object, "SUBSYSTEM_NATIVE_WINDOWS"); yr_set_integer( IMAGE_SUBSYSTEM_WINDOWS_CE_GUI, module_object, "SUBSYSTEM_WINDOWS_CE_GUI"); yr_set_integer( IMAGE_SUBSYSTEM_EFI_APPLICATION, module_object, "SUBSYSTEM_EFI_APPLICATION"); yr_set_integer( IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, module_object, "SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER"); yr_set_integer( IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER, module_object, "SUBSYSTEM_EFI_RUNTIME_DRIVER"); yr_set_integer( IMAGE_SUBSYSTEM_EFI_ROM_IMAGE, module_object, "SUBSYSTEM_EFI_ROM_IMAGE"); yr_set_integer(IMAGE_SUBSYSTEM_XBOX, module_object, "SUBSYSTEM_XBOX"); yr_set_integer( IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION, module_object, "SUBSYSTEM_WINDOWS_BOOT_APPLICATION"); yr_set_integer( IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA, module_object, "HIGH_ENTROPY_VA"); yr_set_integer( IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE, module_object, "DYNAMIC_BASE"); yr_set_integer( IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY, module_object, "FORCE_INTEGRITY"); yr_set_integer( IMAGE_DLLCHARACTERISTICS_NX_COMPAT, module_object, "NX_COMPAT"); yr_set_integer( IMAGE_DLLCHARACTERISTICS_NO_ISOLATION, module_object, "NO_ISOLATION"); yr_set_integer(IMAGE_DLLCHARACTERISTICS_NO_SEH, module_object, "NO_SEH"); yr_set_integer(IMAGE_DLLCHARACTERISTICS_NO_BIND, module_object, "NO_BIND"); yr_set_integer( IMAGE_DLLCHARACTERISTICS_APPCONTAINER, module_object, "APPCONTAINER"); yr_set_integer( IMAGE_DLLCHARACTERISTICS_WDM_DRIVER, module_object, "WDM_DRIVER"); yr_set_integer(IMAGE_DLLCHARACTERISTICS_GUARD_CF, module_object, "GUARD_CF"); yr_set_integer( IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE, module_object, "TERMINAL_SERVER_AWARE"); yr_set_integer(IMAGE_FILE_RELOCS_STRIPPED, module_object, "RELOCS_STRIPPED"); yr_set_integer( IMAGE_FILE_EXECUTABLE_IMAGE, module_object, "EXECUTABLE_IMAGE"); yr_set_integer( IMAGE_FILE_LINE_NUMS_STRIPPED, module_object, "LINE_NUMS_STRIPPED"); yr_set_integer( IMAGE_FILE_LOCAL_SYMS_STRIPPED, module_object, "LOCAL_SYMS_STRIPPED"); yr_set_integer( IMAGE_FILE_AGGRESIVE_WS_TRIM, module_object, "AGGRESIVE_WS_TRIM"); yr_set_integer( IMAGE_FILE_LARGE_ADDRESS_AWARE, module_object, "LARGE_ADDRESS_AWARE"); yr_set_integer( IMAGE_FILE_BYTES_REVERSED_LO, module_object, "BYTES_REVERSED_LO"); yr_set_integer(IMAGE_FILE_32BIT_MACHINE, module_object, "MACHINE_32BIT"); yr_set_integer(IMAGE_FILE_DEBUG_STRIPPED, module_object, "DEBUG_STRIPPED"); yr_set_integer( IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP, module_object, "REMOVABLE_RUN_FROM_SWAP"); yr_set_integer( IMAGE_FILE_NET_RUN_FROM_SWAP, module_object, "NET_RUN_FROM_SWAP"); yr_set_integer(IMAGE_FILE_SYSTEM, module_object, "SYSTEM"); yr_set_integer(IMAGE_FILE_DLL, module_object, "DLL"); yr_set_integer(IMAGE_FILE_UP_SYSTEM_ONLY, module_object, "UP_SYSTEM_ONLY"); yr_set_integer( IMAGE_FILE_BYTES_REVERSED_HI, module_object, "BYTES_REVERSED_HI"); yr_set_integer( IMAGE_DIRECTORY_ENTRY_EXPORT, module_object, "IMAGE_DIRECTORY_ENTRY_EXPORT"); yr_set_integer( IMAGE_DIRECTORY_ENTRY_IMPORT, module_object, "IMAGE_DIRECTORY_ENTRY_IMPORT"); yr_set_integer( IMAGE_DIRECTORY_ENTRY_RESOURCE, module_object, "IMAGE_DIRECTORY_ENTRY_RESOURCE"); yr_set_integer( IMAGE_DIRECTORY_ENTRY_EXCEPTION, module_object, "IMAGE_DIRECTORY_ENTRY_EXCEPTION"); yr_set_integer( IMAGE_DIRECTORY_ENTRY_SECURITY, module_object, "IMAGE_DIRECTORY_ENTRY_SECURITY"); yr_set_integer( IMAGE_DIRECTORY_ENTRY_BASERELOC, module_object, "IMAGE_DIRECTORY_ENTRY_BASERELOC"); yr_set_integer( IMAGE_DIRECTORY_ENTRY_DEBUG, module_object, "IMAGE_DIRECTORY_ENTRY_DEBUG"); yr_set_integer( IMAGE_DIRECTORY_ENTRY_ARCHITECTURE, module_object, "IMAGE_DIRECTORY_ENTRY_ARCHITECTURE"); yr_set_integer( IMAGE_DIRECTORY_ENTRY_COPYRIGHT, module_object, "IMAGE_DIRECTORY_ENTRY_COPYRIGHT"); yr_set_integer( IMAGE_DIRECTORY_ENTRY_GLOBALPTR, module_object, "IMAGE_DIRECTORY_ENTRY_GLOBALPTR"); yr_set_integer( IMAGE_DIRECTORY_ENTRY_TLS, module_object, "IMAGE_DIRECTORY_ENTRY_TLS"); yr_set_integer( IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, module_object, "IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG"); yr_set_integer( IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT, module_object, "IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT"); yr_set_integer( IMAGE_DIRECTORY_ENTRY_IAT, module_object, "IMAGE_DIRECTORY_ENTRY_IAT"); yr_set_integer( IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT, module_object, "IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT"); yr_set_integer( IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR, module_object, "IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR"); yr_set_integer( IMAGE_NT_OPTIONAL_HDR32_MAGIC, module_object, "IMAGE_NT_OPTIONAL_HDR32_MAGIC"); yr_set_integer( IMAGE_NT_OPTIONAL_HDR64_MAGIC, module_object, "IMAGE_NT_OPTIONAL_HDR64_MAGIC"); yr_set_integer( IMAGE_ROM_OPTIONAL_HDR_MAGIC, module_object, "IMAGE_ROM_OPTIONAL_HDR_MAGIC"); yr_set_integer(IMAGE_SCN_TYPE_NO_PAD, module_object, "SECTION_NO_PAD"); yr_set_integer(IMAGE_SCN_CNT_CODE, module_object, "SECTION_CNT_CODE"); yr_set_integer( IMAGE_SCN_CNT_INITIALIZED_DATA, module_object, "SECTION_CNT_INITIALIZED_DATA"); yr_set_integer( IMAGE_SCN_CNT_UNINITIALIZED_DATA, module_object, "SECTION_CNT_UNINITIALIZED_DATA"); yr_set_integer(IMAGE_SCN_LNK_OTHER, module_object, "SECTION_LNK_OTHER"); yr_set_integer(IMAGE_SCN_LNK_INFO, module_object, "SECTION_LNK_INFO"); yr_set_integer(IMAGE_SCN_LNK_REMOVE, module_object, "SECTION_LNK_REMOVE"); yr_set_integer(IMAGE_SCN_LNK_COMDAT, module_object, "SECTION_LNK_COMDAT"); yr_set_integer( IMAGE_SCN_NO_DEFER_SPEC_EXC, module_object, "SECTION_NO_DEFER_SPEC_EXC"); yr_set_integer(IMAGE_SCN_GPREL, module_object, "SECTION_GPREL"); yr_set_integer(IMAGE_SCN_MEM_FARDATA, module_object, "SECTION_MEM_FARDATA"); yr_set_integer( IMAGE_SCN_MEM_PURGEABLE, module_object, "SECTION_MEM_PURGEABLE"); yr_set_integer(IMAGE_SCN_MEM_16BIT, module_object, "SECTION_MEM_16BIT"); yr_set_integer(IMAGE_SCN_MEM_LOCKED, module_object, "SECTION_MEM_LOCKED"); yr_set_integer(IMAGE_SCN_MEM_PRELOAD, module_object, "SECTION_MEM_PRELOAD"); yr_set_integer(IMAGE_SCN_ALIGN_1BYTES, module_object, "SECTION_ALIGN_1BYTES"); yr_set_integer(IMAGE_SCN_ALIGN_2BYTES, module_object, "SECTION_ALIGN_2BYTES"); yr_set_integer(IMAGE_SCN_ALIGN_4BYTES, module_object, "SECTION_ALIGN_4BYTES"); yr_set_integer(IMAGE_SCN_ALIGN_8BYTES, module_object, "SECTION_ALIGN_8BYTES"); yr_set_integer( IMAGE_SCN_ALIGN_16BYTES, module_object, "SECTION_ALIGN_16BYTES"); yr_set_integer( IMAGE_SCN_ALIGN_32BYTES, module_object, "SECTION_ALIGN_32BYTES"); yr_set_integer( IMAGE_SCN_ALIGN_64BYTES, module_object, "SECTION_ALIGN_64BYTES"); yr_set_integer( IMAGE_SCN_ALIGN_128BYTES, module_object, "SECTION_ALIGN_128BYTES"); yr_set_integer( IMAGE_SCN_ALIGN_256BYTES, module_object, "SECTION_ALIGN_256BYTES"); yr_set_integer( IMAGE_SCN_ALIGN_512BYTES, module_object, "SECTION_ALIGN_512BYTES"); yr_set_integer( IMAGE_SCN_ALIGN_1024BYTES, module_object, "SECTION_ALIGN_1024BYTES"); yr_set_integer( IMAGE_SCN_ALIGN_2048BYTES, module_object, "SECTION_ALIGN_2048BYTES"); yr_set_integer( IMAGE_SCN_ALIGN_4096BYTES, module_object, "SECTION_ALIGN_4096BYTES"); yr_set_integer( IMAGE_SCN_ALIGN_8192BYTES, module_object, "SECTION_ALIGN_8192BYTES"); yr_set_integer(IMAGE_SCN_ALIGN_MASK, module_object, "SECTION_ALIGN_MASK"); yr_set_integer( IMAGE_SCN_LNK_NRELOC_OVFL, module_object, "SECTION_LNK_NRELOC_OVFL"); yr_set_integer( IMAGE_SCN_MEM_DISCARDABLE, module_object, "SECTION_MEM_DISCARDABLE"); yr_set_integer( IMAGE_SCN_MEM_NOT_CACHED, module_object, "SECTION_MEM_NOT_CACHED"); yr_set_integer( IMAGE_SCN_MEM_NOT_PAGED, module_object, "SECTION_MEM_NOT_PAGED"); yr_set_integer(IMAGE_SCN_MEM_SHARED, module_object, "SECTION_MEM_SHARED"); yr_set_integer(IMAGE_SCN_MEM_EXECUTE, module_object, "SECTION_MEM_EXECUTE"); yr_set_integer(IMAGE_SCN_MEM_READ, module_object, "SECTION_MEM_READ"); yr_set_integer(IMAGE_SCN_MEM_WRITE, module_object, "SECTION_MEM_WRITE"); yr_set_integer(IMAGE_SCN_SCALE_INDEX, module_object, "SECTION_SCALE_INDEX"); yr_set_integer(RESOURCE_TYPE_CURSOR, module_object, "RESOURCE_TYPE_CURSOR"); yr_set_integer(RESOURCE_TYPE_BITMAP, module_object, "RESOURCE_TYPE_BITMAP"); yr_set_integer(RESOURCE_TYPE_ICON, module_object, "RESOURCE_TYPE_ICON"); yr_set_integer(RESOURCE_TYPE_MENU, module_object, "RESOURCE_TYPE_MENU"); yr_set_integer(RESOURCE_TYPE_DIALOG, module_object, "RESOURCE_TYPE_DIALOG"); yr_set_integer(RESOURCE_TYPE_STRING, module_object, "RESOURCE_TYPE_STRING"); yr_set_integer(RESOURCE_TYPE_FONTDIR, module_object, "RESOURCE_TYPE_FONTDIR"); yr_set_integer(RESOURCE_TYPE_FONT, module_object, "RESOURCE_TYPE_FONT"); yr_set_integer( RESOURCE_TYPE_ACCELERATOR, module_object, "RESOURCE_TYPE_ACCELERATOR"); yr_set_integer(RESOURCE_TYPE_RCDATA, module_object, "RESOURCE_TYPE_RCDATA"); yr_set_integer( RESOURCE_TYPE_MESSAGETABLE, module_object, "RESOURCE_TYPE_MESSAGETABLE"); yr_set_integer( RESOURCE_TYPE_GROUP_CURSOR, module_object, "RESOURCE_TYPE_GROUP_CURSOR"); yr_set_integer( RESOURCE_TYPE_GROUP_ICON, module_object, "RESOURCE_TYPE_GROUP_ICON"); yr_set_integer(RESOURCE_TYPE_VERSION, module_object, "RESOURCE_TYPE_VERSION"); yr_set_integer( RESOURCE_TYPE_DLGINCLUDE, module_object, "RESOURCE_TYPE_DLGINCLUDE"); yr_set_integer( RESOURCE_TYPE_PLUGPLAY, module_object, "RESOURCE_TYPE_PLUGPLAY"); yr_set_integer(RESOURCE_TYPE_VXD, module_object, "RESOURCE_TYPE_VXD"); yr_set_integer( RESOURCE_TYPE_ANICURSOR, module_object, "RESOURCE_TYPE_ANICURSOR"); yr_set_integer(RESOURCE_TYPE_ANIICON, module_object, "RESOURCE_TYPE_ANIICON"); yr_set_integer(RESOURCE_TYPE_HTML, module_object, "RESOURCE_TYPE_HTML"); yr_set_integer( RESOURCE_TYPE_MANIFEST, module_object, "RESOURCE_TYPE_MANIFEST"); yr_set_integer( IMAGE_DEBUG_TYPE_UNKNOWN, module_object, "IMAGE_DEBUG_TYPE_UNKNOWN"); yr_set_integer(IMAGE_DEBUG_TYPE_COFF, module_object, "IMAGE_DEBUG_TYPE_COFF"); yr_set_integer( IMAGE_DEBUG_TYPE_CODEVIEW, module_object, "IMAGE_DEBUG_TYPE_CODEVIEW"); yr_set_integer(IMAGE_DEBUG_TYPE_FPO, module_object, "IMAGE_DEBUG_TYPE_FPO"); yr_set_integer(IMAGE_DEBUG_TYPE_MISC, module_object, "IMAGE_DEBUG_TYPE_MISC"); yr_set_integer( IMAGE_DEBUG_TYPE_EXCEPTION, module_object, "IMAGE_DEBUG_TYPE_EXCEPTION"); yr_set_integer( IMAGE_DEBUG_TYPE_FIXUP, module_object, "IMAGE_DEBUG_TYPE_FIXUP"); yr_set_integer( IMAGE_DEBUG_TYPE_OMAP_TO_SRC, module_object, "IMAGE_DEBUG_TYPE_OMAP_TO_SRC"); yr_set_integer( IMAGE_DEBUG_TYPE_OMAP_FROM_SRC, module_object, "IMAGE_DEBUG_TYPE_OMAP_FROM_SRC"); yr_set_integer( IMAGE_DEBUG_TYPE_BORLAND, module_object, "IMAGE_DEBUG_TYPE_BORLAND"); yr_set_integer( IMAGE_DEBUG_TYPE_RESERVED10, module_object, "IMAGE_DEBUG_TYPE_RESERVED10"); yr_set_integer( IMAGE_DEBUG_TYPE_CLSID, module_object, "IMAGE_DEBUG_TYPE_CLSID"); yr_set_integer( IMAGE_DEBUG_TYPE_VC_FEATURE, module_object, "IMAGE_DEBUG_TYPE_VC_FEATURE"); yr_set_integer(IMAGE_DEBUG_TYPE_POGO, module_object, "IMAGE_DEBUG_TYPE_POGO"); yr_set_integer( IMAGE_DEBUG_TYPE_ILTCG, module_object, "IMAGE_DEBUG_TYPE_ILTCG"); yr_set_integer(IMAGE_DEBUG_TYPE_MPX, module_object, "IMAGE_DEBUG_TYPE_MPX"); yr_set_integer( IMAGE_DEBUG_TYPE_REPRO, module_object, "IMAGE_DEBUG_TYPE_REPRO"); yr_set_integer(0, module_object, "is_pe"); foreach_memory_block(iterator, block) { block_data = yr_fetch_block_data(block); if (block_data == NULL) continue; pe_header = pe_get_header(block_data, block->size); if (pe_header != NULL) { // Ignore DLLs while scanning a process if (!(context->flags & SCAN_FLAGS_PROCESS_MEMORY) || !(yr_le16toh(pe_header->FileHeader.Characteristics) & IMAGE_FILE_DLL)) { pe = (PE*) yr_malloc(sizeof(PE)); if (pe == NULL) return ERROR_INSUFFICIENT_MEMORY; FAIL_ON_ERROR_WITH_CLEANUP( yr_hash_table_create(17, &pe->hash_table), yr_free(pe)); pe->data = block_data; pe->data_size = block->size; pe->header = pe_header; pe->object = module_object; pe->resources = 0; pe->version_infos = 0; module_object->data = pe; pe_parse_header(pe, block->base, context->flags); pe_parse_rich_signature(pe, block->base); pe_parse_debug_directory(pe); #if defined(HAVE_LIBCRYPTO) && !defined(BORINGSSL) pe_parse_certificates(pe); #endif pe->imported_dlls = pe_parse_imports(pe); pe->delay_imported_dlls = pe_parse_delayed_imports(pe); pe_parse_exports(pe); break; } } } return ERROR_SUCCESS; } void free_dlls(IMPORTED_DLL* dll) { IMPORTED_DLL* next_dll = NULL; IMPORT_FUNCTION* func = NULL; IMPORT_FUNCTION* next_func = NULL; while (dll) { if (dll->name) yr_free(dll->name); func = dll->functions; while (func) { if (func->name) yr_free(func->name); next_func = func->next; yr_free(func); func = next_func; } next_dll = dll->next; yr_free(dll); dll = next_dll; } } int module_unload(YR_OBJECT* module_object) { PE* pe = (PE*) module_object->data; if (pe == NULL) return ERROR_SUCCESS; if (pe->hash_table != NULL) yr_hash_table_destroy( pe->hash_table, (YR_HASH_TABLE_FREE_VALUE_FUNC) yr_free); free_dlls(pe->imported_dlls); free_dlls(pe->delay_imported_dlls); yr_free(pe); return ERROR_SUCCESS; } yara-4.5.3/libyara/modules/pe/pe_utils.c000066400000000000000000001222261501365277300201640ustar00rootroot00000000000000/* Copyright (c) 2014-2015. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include PIMAGE_NT_HEADERS32 pe_get_header(const uint8_t* data, size_t data_size) { PIMAGE_DOS_HEADER mz_header; PIMAGE_NT_HEADERS32 pe_header; size_t headers_size = 0; if (data_size < sizeof(IMAGE_DOS_HEADER)) return NULL; mz_header = (PIMAGE_DOS_HEADER) data; if (yr_le16toh(mz_header->e_magic) != IMAGE_DOS_SIGNATURE) return NULL; if (yr_le32toh(mz_header->e_lfanew) < 0) return NULL; headers_size = yr_le32toh(mz_header->e_lfanew) + sizeof(pe_header->Signature) + sizeof(IMAGE_FILE_HEADER); if (data_size < headers_size) return NULL; pe_header = (PIMAGE_NT_HEADERS32) (data + yr_le32toh(mz_header->e_lfanew)); if (yr_le32toh(pe_header->Signature) != IMAGE_NT_SIGNATURE) return NULL; if (data_size < headers_size + sizeof(IMAGE_OPTIONAL_HEADER32)) return NULL; if (pe_header->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) headers_size += sizeof(IMAGE_OPTIONAL_HEADER64); else headers_size += sizeof(IMAGE_OPTIONAL_HEADER32); if (data_size < headers_size) return NULL; return pe_header; } PIMAGE_DATA_DIRECTORY pe_get_directory_entry(PE* pe, int entry) { // In theory, `entry` should be lower than NumberOfRvaAndSizes, however, // we don't enforce it because some PE files have a NumberOfRvaAndSizes // values lower than the actual number of directory entries. For example, // file 0aa527fd26c8e7fa7f3476b6d7eb8f22c071ff4c0fd3ed3797fa90ceb80f24ce // has NumberOfRvaAndSizes set to 0, but it actually has directory // entries. If we are overly strict here, and only parse entries which are // less than NumberOfRvaAndSizes, we run the risk of missing otherwise // perfectly valid files (valid in the sense that they can be parsed, even // if they are not valid for the Windows loader). PIMAGE_DATA_DIRECTORY result = &OptionalHeader(pe, DataDirectory)[entry]; // Check that directory is in file if (!struct_fits_in_pe(pe, result, IMAGE_DATA_DIRECTORY)) return NULL; return result; } int64_t pe_rva_to_offset(PE* pe, uint64_t rva) { PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pe->header); DWORD lowest_section_rva = 0xffffffff; DWORD section_rva = 0; DWORD section_offset = 0; DWORD section_raw_size = 0; int64_t result; int i = 0; int alignment = 0; int rest = 0; while (i < yr_min( yr_le16toh(pe->header->FileHeader.NumberOfSections), MAX_PE_SECTIONS)) { if (struct_fits_in_pe(pe, section, IMAGE_SECTION_HEADER)) { if (lowest_section_rva > yr_le32toh(section->VirtualAddress)) { lowest_section_rva = yr_le32toh(section->VirtualAddress); } // In theory, we should use the section's virtual size while // checking if some RVA is within the section. In most cases // the virtual size is greater than the raw data size, but that's // not always the case. So we use the larger of the two values. // // Example: // db6a9934570fa98a93a979e7e0e218e0c9710e5a787b18c6948f2eedd9338984 uint32_t virtualSize = yr_max( yr_le32toh(section->Misc.VirtualSize), yr_le32toh(section->SizeOfRawData)); if (rva >= yr_le32toh(section->VirtualAddress) && rva - yr_le32toh(section->VirtualAddress) < virtualSize && section_rva <= yr_le32toh(section->VirtualAddress)) { // Round section_offset // // Rounding everything less than 0x200 to 0 as discussed in // https://code.google.com/archive/p/corkami/wikis/PE.wiki#PointerToRawData // does not work for PE32_FILE from the test suite and for // some tinype samples where File Alignment = 4 // (http://www.phreedom.org/research/tinype/). // // If FileAlignment is >= 0x200, it is apparently ignored (see // Ero Carreras's pefile.py, PE.adjust_FileAlignment). alignment = yr_min( yr_le32toh(OptionalHeader(pe, FileAlignment)), 0x200); section_rva = yr_le32toh(section->VirtualAddress); section_offset = yr_le32toh(section->PointerToRawData); section_raw_size = yr_le32toh(section->SizeOfRawData); if (alignment) { rest = section_offset % alignment; if (rest) section_offset -= rest; } // For multi-section images, real pointer to raw data is aligned down to // sector size if (yr_le32toh(OptionalHeader(pe, SectionAlignment)) >= PE_PAGE_SIZE) section_offset = section_offset & ~(PE_SECTOR_SIZE - 1); } section++; i++; } else { return -1; } } // Everything before the first section seems to get mapped straight // relative to ImageBase. if (rva < lowest_section_rva) { section_rva = 0; section_offset = 0; section_raw_size = (DWORD) pe->data_size; } // Many sections, have a raw (on disk) size smaller than their in-memory size. // Check for rva's that map to this sparse space, and therefore have no valid // associated file offset. if ((rva - section_rva) >= section_raw_size) return -1; result = section_offset + (rva - section_rva); // Check that the offset fits within the file. if (result >= pe->data_size) return -1; return result; } #if !HAVE_TIMEGM #if HAVE__MKGMTIME #define timegm _mkgmtime #else #include static bool is_leap(unsigned int year) { year += 1900; return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0); } time_t timegm(struct tm* tm) { static const unsigned ndays[2][12] = { {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; time_t res = 0; int i; for (i = 70; i < tm->tm_year; ++i) res += is_leap(i) ? 366 : 365; for (i = 0; i < tm->tm_mon; ++i) res += ndays[is_leap(tm->tm_year)][i]; res += tm->tm_mday - 1; res *= 24; res += tm->tm_hour; res *= 60; res += tm->tm_min; res *= 60; res += tm->tm_sec; return res; } #endif // HAVE__MKGMTIME #endif // !HAVE_TIMEGM // These ordinals are taken from pefile. If a lookup fails attempt to return // "ordN" and if that fails, return NULL. The caller is responsible for freeing // the returned string. char* ord_lookup(char* dll, uint16_t ord) { char name[64]; name[0] = '\0'; if (strncasecmp(dll, "WS2_32.dll", 10) == 0 || strncasecmp(dll, "wsock32.dll", 11) == 0) { switch (ord) { case 1: sprintf(name, "accept"); break; case 2: sprintf(name, "bind"); break; case 3: sprintf(name, "closesocket"); break; case 4: sprintf(name, "connect"); break; case 5: sprintf(name, "getpeername"); break; case 6: sprintf(name, "getsockname"); break; case 7: sprintf(name, "getsockopt"); break; case 8: sprintf(name, "htonl"); break; case 9: sprintf(name, "htons"); break; case 10: sprintf(name, "ioctlsocket"); break; case 11: sprintf(name, "inet_addr"); break; case 12: sprintf(name, "inet_ntoa"); break; case 13: sprintf(name, "listen"); break; case 14: sprintf(name, "ntohl"); break; case 15: sprintf(name, "ntohs"); break; case 16: sprintf(name, "recv"); break; case 17: sprintf(name, "recvfrom"); break; case 18: sprintf(name, "select"); break; case 19: sprintf(name, "send"); break; case 20: sprintf(name, "sendto"); break; case 21: sprintf(name, "setsockopt"); break; case 22: sprintf(name, "shutdown"); break; case 23: sprintf(name, "socket"); break; case 24: sprintf(name, "GetAddrInfoW"); break; case 25: sprintf(name, "GetNameInfoW"); break; case 26: sprintf(name, "WSApSetPostRoutine"); break; case 27: sprintf(name, "FreeAddrInfoW"); break; case 28: sprintf(name, "WPUCompleteOverlappedRequest"); break; case 29: sprintf(name, "WSAAccept"); break; case 30: sprintf(name, "WSAAddressToStringA"); break; case 31: sprintf(name, "WSAAddressToStringW"); break; case 32: sprintf(name, "WSACloseEvent"); break; case 33: sprintf(name, "WSAConnect"); break; case 34: sprintf(name, "WSACreateEvent"); break; case 35: sprintf(name, "WSADuplicateSocketA"); break; case 36: sprintf(name, "WSADuplicateSocketW"); break; case 37: sprintf(name, "WSAEnumNameSpaceProvidersA"); break; case 38: sprintf(name, "WSAEnumNameSpaceProvidersW"); break; case 39: sprintf(name, "WSAEnumNetworkEvents"); break; case 40: sprintf(name, "WSAEnumProtocolsA"); break; case 41: sprintf(name, "WSAEnumProtocolsW"); break; case 42: sprintf(name, "WSAEventSelect"); break; case 43: sprintf(name, "WSAGetOverlappedResult"); break; case 44: sprintf(name, "WSAGetQOSByName"); break; case 45: sprintf(name, "WSAGetServiceClassInfoA"); break; case 46: sprintf(name, "WSAGetServiceClassInfoW"); break; case 47: sprintf(name, "WSAGetServiceClassNameByClassIdA"); break; case 48: sprintf(name, "WSAGetServiceClassNameByClassIdW"); break; case 49: sprintf(name, "WSAHtonl"); break; case 50: sprintf(name, "WSAHtons"); break; case 51: sprintf(name, "gethostbyaddr"); break; case 52: sprintf(name, "gethostbyname"); break; case 53: sprintf(name, "getprotobyname"); break; case 54: sprintf(name, "getprotobynumber"); break; case 55: sprintf(name, "getservbyname"); break; case 56: sprintf(name, "getservbyport"); break; case 57: sprintf(name, "gethostname"); break; case 58: sprintf(name, "WSAInstallServiceClassA"); break; case 59: sprintf(name, "WSAInstallServiceClassW"); break; case 60: sprintf(name, "WSAIoctl"); break; case 61: sprintf(name, "WSAJoinLeaf"); break; case 62: sprintf(name, "WSALookupServiceBeginA"); break; case 63: sprintf(name, "WSALookupServiceBeginW"); break; case 64: sprintf(name, "WSALookupServiceEnd"); break; case 65: sprintf(name, "WSALookupServiceNextA"); break; case 66: sprintf(name, "WSALookupServiceNextW"); break; case 67: sprintf(name, "WSANSPIoctl"); break; case 68: sprintf(name, "WSANtohl"); break; case 69: sprintf(name, "WSANtohs"); break; case 70: sprintf(name, "WSAProviderConfigChange"); break; case 71: sprintf(name, "WSARecv"); break; case 72: sprintf(name, "WSARecvDisconnect"); break; case 73: sprintf(name, "WSARecvFrom"); break; case 74: sprintf(name, "WSARemoveServiceClass"); break; case 75: sprintf(name, "WSAResetEvent"); break; case 76: sprintf(name, "WSASend"); break; case 77: sprintf(name, "WSASendDisconnect"); break; case 78: sprintf(name, "WSASendTo"); break; case 79: sprintf(name, "WSASetEvent"); break; case 80: sprintf(name, "WSASetServiceA"); break; case 81: sprintf(name, "WSASetServiceW"); break; case 82: sprintf(name, "WSASocketA"); break; case 83: sprintf(name, "WSASocketW"); break; case 84: sprintf(name, "WSAStringToAddressA"); break; case 85: sprintf(name, "WSAStringToAddressW"); break; case 86: sprintf(name, "WSAWaitForMultipleEvents"); break; case 87: sprintf(name, "WSCDeinstallProvider"); break; case 88: sprintf(name, "WSCEnableNSProvider"); break; case 89: sprintf(name, "WSCEnumProtocols"); break; case 90: sprintf(name, "WSCGetProviderPath"); break; case 91: sprintf(name, "WSCInstallNameSpace"); break; case 92: sprintf(name, "WSCInstallProvider"); break; case 93: sprintf(name, "WSCUnInstallNameSpace"); break; case 94: sprintf(name, "WSCUpdateProvider"); break; case 95: sprintf(name, "WSCWriteNameSpaceOrder"); break; case 96: sprintf(name, "WSCWriteProviderOrder"); break; case 97: sprintf(name, "freeaddrinfo"); break; case 98: sprintf(name, "getaddrinfo"); break; case 99: sprintf(name, "getnameinfo"); break; case 101: sprintf(name, "WSAAsyncSelect"); break; case 102: sprintf(name, "WSAAsyncGetHostByAddr"); break; case 103: sprintf(name, "WSAAsyncGetHostByName"); break; case 104: sprintf(name, "WSAAsyncGetProtoByNumber"); break; case 105: sprintf(name, "WSAAsyncGetProtoByName"); break; case 106: sprintf(name, "WSAAsyncGetServByPort"); break; case 107: sprintf(name, "WSAAsyncGetServByName"); break; case 108: sprintf(name, "WSACancelAsyncRequest"); break; case 109: sprintf(name, "WSASetBlockingHook"); break; case 110: sprintf(name, "WSAUnhookBlockingHook"); break; case 111: sprintf(name, "WSAGetLastError"); break; case 112: sprintf(name, "WSASetLastError"); break; case 113: sprintf(name, "WSACancelBlockingCall"); break; case 114: sprintf(name, "WSAIsBlocking"); break; case 115: sprintf(name, "WSAStartup"); break; case 116: sprintf(name, "WSACleanup"); break; case 151: sprintf(name, "__WSAFDIsSet"); break; case 500: sprintf(name, "WEP"); break; default: break; } } else if (strncasecmp(dll, "oleaut32.dll", 12) == 0) { switch (ord) { case 2: sprintf(name, "SysAllocString"); break; case 3: sprintf(name, "SysReAllocString"); break; case 4: sprintf(name, "SysAllocStringLen"); break; case 5: sprintf(name, "SysReAllocStringLen"); break; case 6: sprintf(name, "SysFreeString"); break; case 7: sprintf(name, "SysStringLen"); break; case 8: sprintf(name, "VariantInit"); break; case 9: sprintf(name, "VariantClear"); break; case 10: sprintf(name, "VariantCopy"); break; case 11: sprintf(name, "VariantCopyInd"); break; case 12: sprintf(name, "VariantChangeType"); break; case 13: sprintf(name, "VariantTimeToDosDateTime"); break; case 14: sprintf(name, "DosDateTimeToVariantTime"); break; case 15: sprintf(name, "SafeArrayCreate"); break; case 16: sprintf(name, "SafeArrayDestroy"); break; case 17: sprintf(name, "SafeArrayGetDim"); break; case 18: sprintf(name, "SafeArrayGetElemsize"); break; case 19: sprintf(name, "SafeArrayGetUBound"); break; case 20: sprintf(name, "SafeArrayGetLBound"); break; case 21: sprintf(name, "SafeArrayLock"); break; case 22: sprintf(name, "SafeArrayUnlock"); break; case 23: sprintf(name, "SafeArrayAccessData"); break; case 24: sprintf(name, "SafeArrayUnaccessData"); break; case 25: sprintf(name, "SafeArrayGetElement"); break; case 26: sprintf(name, "SafeArrayPutElement"); break; case 27: sprintf(name, "SafeArrayCopy"); break; case 28: sprintf(name, "DispGetParam"); break; case 29: sprintf(name, "DispGetIDsOfNames"); break; case 30: sprintf(name, "DispInvoke"); break; case 31: sprintf(name, "CreateDispTypeInfo"); break; case 32: sprintf(name, "CreateStdDispatch"); break; case 33: sprintf(name, "RegisterActiveObject"); break; case 34: sprintf(name, "RevokeActiveObject"); break; case 35: sprintf(name, "GetActiveObject"); break; case 36: sprintf(name, "SafeArrayAllocDescriptor"); break; case 37: sprintf(name, "SafeArrayAllocData"); break; case 38: sprintf(name, "SafeArrayDestroyDescriptor"); break; case 39: sprintf(name, "SafeArrayDestroyData"); break; case 40: sprintf(name, "SafeArrayRedim"); break; case 41: sprintf(name, "SafeArrayAllocDescriptorEx"); break; case 42: sprintf(name, "SafeArrayCreateEx"); break; case 43: sprintf(name, "SafeArrayCreateVectorEx"); break; case 44: sprintf(name, "SafeArraySetRecordInfo"); break; case 45: sprintf(name, "SafeArrayGetRecordInfo"); break; case 46: sprintf(name, "VarParseNumFromStr"); break; case 47: sprintf(name, "VarNumFromParseNum"); break; case 48: sprintf(name, "VarI2FromUI1"); break; case 49: sprintf(name, "VarI2FromI4"); break; case 50: sprintf(name, "VarI2FromR4"); break; case 51: sprintf(name, "VarI2FromR8"); break; case 52: sprintf(name, "VarI2FromCy"); break; case 53: sprintf(name, "VarI2FromDate"); break; case 54: sprintf(name, "VarI2FromStr"); break; case 55: sprintf(name, "VarI2FromDisp"); break; case 56: sprintf(name, "VarI2FromBool"); break; case 57: sprintf(name, "SafeArraySetIID"); break; case 58: sprintf(name, "VarI4FromUI1"); break; case 59: sprintf(name, "VarI4FromI2"); break; case 60: sprintf(name, "VarI4FromR4"); break; case 61: sprintf(name, "VarI4FromR8"); break; case 62: sprintf(name, "VarI4FromCy"); break; case 63: sprintf(name, "VarI4FromDate"); break; case 64: sprintf(name, "VarI4FromStr"); break; case 65: sprintf(name, "VarI4FromDisp"); break; case 66: sprintf(name, "VarI4FromBool"); break; case 67: sprintf(name, "SafeArrayGetIID"); break; case 68: sprintf(name, "VarR4FromUI1"); break; case 69: sprintf(name, "VarR4FromI2"); break; case 70: sprintf(name, "VarR4FromI4"); break; case 71: sprintf(name, "VarR4FromR8"); break; case 72: sprintf(name, "VarR4FromCy"); break; case 73: sprintf(name, "VarR4FromDate"); break; case 74: sprintf(name, "VarR4FromStr"); break; case 75: sprintf(name, "VarR4FromDisp"); break; case 76: sprintf(name, "VarR4FromBool"); break; case 77: sprintf(name, "SafeArrayGetVartype"); break; case 78: sprintf(name, "VarR8FromUI1"); break; case 79: sprintf(name, "VarR8FromI2"); break; case 80: sprintf(name, "VarR8FromI4"); break; case 81: sprintf(name, "VarR8FromR4"); break; case 82: sprintf(name, "VarR8FromCy"); break; case 83: sprintf(name, "VarR8FromDate"); break; case 84: sprintf(name, "VarR8FromStr"); break; case 85: sprintf(name, "VarR8FromDisp"); break; case 86: sprintf(name, "VarR8FromBool"); break; case 87: sprintf(name, "VarFormat"); break; case 88: sprintf(name, "VarDateFromUI1"); break; case 89: sprintf(name, "VarDateFromI2"); break; case 90: sprintf(name, "VarDateFromI4"); break; case 91: sprintf(name, "VarDateFromR4"); break; case 92: sprintf(name, "VarDateFromR8"); break; case 93: sprintf(name, "VarDateFromCy"); break; case 94: sprintf(name, "VarDateFromStr"); break; case 95: sprintf(name, "VarDateFromDisp"); break; case 96: sprintf(name, "VarDateFromBool"); break; case 97: sprintf(name, "VarFormatDateTime"); break; case 98: sprintf(name, "VarCyFromUI1"); break; case 99: sprintf(name, "VarCyFromI2"); break; case 100: sprintf(name, "VarCyFromI4"); break; case 101: sprintf(name, "VarCyFromR4"); break; case 102: sprintf(name, "VarCyFromR8"); break; case 103: sprintf(name, "VarCyFromDate"); break; case 104: sprintf(name, "VarCyFromStr"); break; case 105: sprintf(name, "VarCyFromDisp"); break; case 106: sprintf(name, "VarCyFromBool"); break; case 107: sprintf(name, "VarFormatNumber"); break; case 108: sprintf(name, "VarBstrFromUI1"); break; case 109: sprintf(name, "VarBstrFromI2"); break; case 110: sprintf(name, "VarBstrFromI4"); break; case 111: sprintf(name, "VarBstrFromR4"); break; case 112: sprintf(name, "VarBstrFromR8"); break; case 113: sprintf(name, "VarBstrFromCy"); break; case 114: sprintf(name, "VarBstrFromDate"); break; case 115: sprintf(name, "VarBstrFromDisp"); break; case 116: sprintf(name, "VarBstrFromBool"); break; case 117: sprintf(name, "VarFormatPercent"); break; case 118: sprintf(name, "VarBoolFromUI1"); break; case 119: sprintf(name, "VarBoolFromI2"); break; case 120: sprintf(name, "VarBoolFromI4"); break; case 121: sprintf(name, "VarBoolFromR4"); break; case 122: sprintf(name, "VarBoolFromR8"); break; case 123: sprintf(name, "VarBoolFromDate"); break; case 124: sprintf(name, "VarBoolFromCy"); break; case 125: sprintf(name, "VarBoolFromStr"); break; case 126: sprintf(name, "VarBoolFromDisp"); break; case 127: sprintf(name, "VarFormatCurrency"); break; case 128: sprintf(name, "VarWeekdayName"); break; case 129: sprintf(name, "VarMonthName"); break; case 130: sprintf(name, "VarUI1FromI2"); break; case 131: sprintf(name, "VarUI1FromI4"); break; case 132: sprintf(name, "VarUI1FromR4"); break; case 133: sprintf(name, "VarUI1FromR8"); break; case 134: sprintf(name, "VarUI1FromCy"); break; case 135: sprintf(name, "VarUI1FromDate"); break; case 136: sprintf(name, "VarUI1FromStr"); break; case 137: sprintf(name, "VarUI1FromDisp"); break; case 138: sprintf(name, "VarUI1FromBool"); break; case 139: sprintf(name, "VarFormatFromTokens"); break; case 140: sprintf(name, "VarTokenizeFormatString"); break; case 141: sprintf(name, "VarAdd"); break; case 142: sprintf(name, "VarAnd"); break; case 143: sprintf(name, "VarDiv"); break; case 144: sprintf(name, "DllCanUnloadNow"); break; case 145: sprintf(name, "DllGetClassObject"); break; case 146: sprintf(name, "DispCallFunc"); break; case 147: sprintf(name, "VariantChangeTypeEx"); break; case 148: sprintf(name, "SafeArrayPtrOfIndex"); break; case 149: sprintf(name, "SysStringByteLen"); break; case 150: sprintf(name, "SysAllocStringByteLen"); break; case 151: sprintf(name, "DllRegisterServer"); break; case 152: sprintf(name, "VarEqv"); break; case 153: sprintf(name, "VarIdiv"); break; case 154: sprintf(name, "VarImp"); break; case 155: sprintf(name, "VarMod"); break; case 156: sprintf(name, "VarMul"); break; case 157: sprintf(name, "VarOr"); break; case 158: sprintf(name, "VarPow"); break; case 159: sprintf(name, "VarSub"); break; case 160: sprintf(name, "CreateTypeLib"); break; case 161: sprintf(name, "LoadTypeLib"); break; case 162: sprintf(name, "LoadRegTypeLib"); break; case 163: sprintf(name, "RegisterTypeLib"); break; case 164: sprintf(name, "QueryPathOfRegTypeLib"); break; case 165: sprintf(name, "LHashValOfNameSys"); break; case 166: sprintf(name, "LHashValOfNameSysA"); break; case 167: sprintf(name, "VarXor"); break; case 168: sprintf(name, "VarAbs"); break; case 169: sprintf(name, "VarFix"); break; case 170: sprintf(name, "OaBuildVersion"); break; case 171: sprintf(name, "ClearCustData"); break; case 172: sprintf(name, "VarInt"); break; case 173: sprintf(name, "VarNeg"); break; case 174: sprintf(name, "VarNot"); break; case 175: sprintf(name, "VarRound"); break; case 176: sprintf(name, "VarCmp"); break; case 177: sprintf(name, "VarDecAdd"); break; case 178: sprintf(name, "VarDecDiv"); break; case 179: sprintf(name, "VarDecMul"); break; case 180: sprintf(name, "CreateTypeLib2"); break; case 181: sprintf(name, "VarDecSub"); break; case 182: sprintf(name, "VarDecAbs"); break; case 183: sprintf(name, "LoadTypeLibEx"); break; case 184: sprintf(name, "SystemTimeToVariantTime"); break; case 185: sprintf(name, "VariantTimeToSystemTime"); break; case 186: sprintf(name, "UnRegisterTypeLib"); break; case 187: sprintf(name, "VarDecFix"); break; case 188: sprintf(name, "VarDecInt"); break; case 189: sprintf(name, "VarDecNeg"); break; case 190: sprintf(name, "VarDecFromUI1"); break; case 191: sprintf(name, "VarDecFromI2"); break; case 192: sprintf(name, "VarDecFromI4"); break; case 193: sprintf(name, "VarDecFromR4"); break; case 194: sprintf(name, "VarDecFromR8"); break; case 195: sprintf(name, "VarDecFromDate"); break; case 196: sprintf(name, "VarDecFromCy"); break; case 197: sprintf(name, "VarDecFromStr"); break; case 198: sprintf(name, "VarDecFromDisp"); break; case 199: sprintf(name, "VarDecFromBool"); break; case 200: sprintf(name, "GetErrorInfo"); break; case 201: sprintf(name, "SetErrorInfo"); break; case 202: sprintf(name, "CreateErrorInfo"); break; case 203: sprintf(name, "VarDecRound"); break; case 204: sprintf(name, "VarDecCmp"); break; case 205: sprintf(name, "VarI2FromI1"); break; case 206: sprintf(name, "VarI2FromUI2"); break; case 207: sprintf(name, "VarI2FromUI4"); break; case 208: sprintf(name, "VarI2FromDec"); break; case 209: sprintf(name, "VarI4FromI1"); break; case 210: sprintf(name, "VarI4FromUI2"); break; case 211: sprintf(name, "VarI4FromUI4"); break; case 212: sprintf(name, "VarI4FromDec"); break; case 213: sprintf(name, "VarR4FromI1"); break; case 214: sprintf(name, "VarR4FromUI2"); break; case 215: sprintf(name, "VarR4FromUI4"); break; case 216: sprintf(name, "VarR4FromDec"); break; case 217: sprintf(name, "VarR8FromI1"); break; case 218: sprintf(name, "VarR8FromUI2"); break; case 219: sprintf(name, "VarR8FromUI4"); break; case 220: sprintf(name, "VarR8FromDec"); break; case 221: sprintf(name, "VarDateFromI1"); break; case 222: sprintf(name, "VarDateFromUI2"); break; case 223: sprintf(name, "VarDateFromUI4"); break; case 224: sprintf(name, "VarDateFromDec"); break; case 225: sprintf(name, "VarCyFromI1"); break; case 226: sprintf(name, "VarCyFromUI2"); break; case 227: sprintf(name, "VarCyFromUI4"); break; case 228: sprintf(name, "VarCyFromDec"); break; case 229: sprintf(name, "VarBstrFromI1"); break; case 230: sprintf(name, "VarBstrFromUI2"); break; case 231: sprintf(name, "VarBstrFromUI4"); break; case 232: sprintf(name, "VarBstrFromDec"); break; case 233: sprintf(name, "VarBoolFromI1"); break; case 234: sprintf(name, "VarBoolFromUI2"); break; case 235: sprintf(name, "VarBoolFromUI4"); break; case 236: sprintf(name, "VarBoolFromDec"); break; case 237: sprintf(name, "VarUI1FromI1"); break; case 238: sprintf(name, "VarUI1FromUI2"); break; case 239: sprintf(name, "VarUI1FromUI4"); break; case 240: sprintf(name, "VarUI1FromDec"); break; case 241: sprintf(name, "VarDecFromI1"); break; case 242: sprintf(name, "VarDecFromUI2"); break; case 243: sprintf(name, "VarDecFromUI4"); break; case 244: sprintf(name, "VarI1FromUI1"); break; case 245: sprintf(name, "VarI1FromI2"); break; case 246: sprintf(name, "VarI1FromI4"); break; case 247: sprintf(name, "VarI1FromR4"); break; case 248: sprintf(name, "VarI1FromR8"); break; case 249: sprintf(name, "VarI1FromDate"); break; case 250: sprintf(name, "VarI1FromCy"); break; case 251: sprintf(name, "VarI1FromStr"); break; case 252: sprintf(name, "VarI1FromDisp"); break; case 253: sprintf(name, "VarI1FromBool"); break; case 254: sprintf(name, "VarI1FromUI2"); break; case 255: sprintf(name, "VarI1FromUI4"); break; case 256: sprintf(name, "VarI1FromDec"); break; case 257: sprintf(name, "VarUI2FromUI1"); break; case 258: sprintf(name, "VarUI2FromI2"); break; case 259: sprintf(name, "VarUI2FromI4"); break; case 260: sprintf(name, "VarUI2FromR4"); break; case 261: sprintf(name, "VarUI2FromR8"); break; case 262: sprintf(name, "VarUI2FromDate"); break; case 263: sprintf(name, "VarUI2FromCy"); break; case 264: sprintf(name, "VarUI2FromStr"); break; case 265: sprintf(name, "VarUI2FromDisp"); break; case 266: sprintf(name, "VarUI2FromBool"); break; case 267: sprintf(name, "VarUI2FromI1"); break; case 268: sprintf(name, "VarUI2FromUI4"); break; case 269: sprintf(name, "VarUI2FromDec"); break; case 270: sprintf(name, "VarUI4FromUI1"); break; case 271: sprintf(name, "VarUI4FromI2"); break; case 272: sprintf(name, "VarUI4FromI4"); break; case 273: sprintf(name, "VarUI4FromR4"); break; case 274: sprintf(name, "VarUI4FromR8"); break; case 275: sprintf(name, "VarUI4FromDate"); break; case 276: sprintf(name, "VarUI4FromCy"); break; case 277: sprintf(name, "VarUI4FromStr"); break; case 278: sprintf(name, "VarUI4FromDisp"); break; case 279: sprintf(name, "VarUI4FromBool"); break; case 280: sprintf(name, "VarUI4FromI1"); break; case 281: sprintf(name, "VarUI4FromUI2"); break; case 282: sprintf(name, "VarUI4FromDec"); break; case 283: sprintf(name, "BSTR_UserSize"); break; case 284: sprintf(name, "BSTR_UserMarshal"); break; case 285: sprintf(name, "BSTR_UserUnmarshal"); break; case 286: sprintf(name, "BSTR_UserFree"); break; case 287: sprintf(name, "VARIANT_UserSize"); break; case 288: sprintf(name, "VARIANT_UserMarshal"); break; case 289: sprintf(name, "VARIANT_UserUnmarshal"); break; case 290: sprintf(name, "VARIANT_UserFree"); break; case 291: sprintf(name, "LPSAFEARRAY_UserSize"); break; case 292: sprintf(name, "LPSAFEARRAY_UserMarshal"); break; case 293: sprintf(name, "LPSAFEARRAY_UserUnmarshal"); break; case 294: sprintf(name, "LPSAFEARRAY_UserFree"); break; case 295: sprintf(name, "LPSAFEARRAY_Size"); break; case 296: sprintf(name, "LPSAFEARRAY_Marshal"); break; case 297: sprintf(name, "LPSAFEARRAY_Unmarshal"); break; case 298: sprintf(name, "VarDecCmpR8"); break; case 299: sprintf(name, "VarCyAdd"); break; case 300: sprintf(name, "DllUnregisterServer"); break; case 301: sprintf(name, "OACreateTypeLib2"); break; case 303: sprintf(name, "VarCyMul"); break; case 304: sprintf(name, "VarCyMulI4"); break; case 305: sprintf(name, "VarCySub"); break; case 306: sprintf(name, "VarCyAbs"); break; case 307: sprintf(name, "VarCyFix"); break; case 308: sprintf(name, "VarCyInt"); break; case 309: sprintf(name, "VarCyNeg"); break; case 310: sprintf(name, "VarCyRound"); break; case 311: sprintf(name, "VarCyCmp"); break; case 312: sprintf(name, "VarCyCmpR8"); break; case 313: sprintf(name, "VarBstrCat"); break; case 314: sprintf(name, "VarBstrCmp"); break; case 315: sprintf(name, "VarR8Pow"); break; case 316: sprintf(name, "VarR4CmpR8"); break; case 317: sprintf(name, "VarR8Round"); break; case 318: sprintf(name, "VarCat"); break; case 319: sprintf(name, "VarDateFromUdateEx"); break; case 322: sprintf(name, "GetRecordInfoFromGuids"); break; case 323: sprintf(name, "GetRecordInfoFromTypeInfo"); break; case 325: sprintf(name, "SetVarConversionLocaleSetting"); break; case 326: sprintf(name, "GetVarConversionLocaleSetting"); break; case 327: sprintf(name, "SetOaNoCache"); break; case 329: sprintf(name, "VarCyMulI8"); break; case 330: sprintf(name, "VarDateFromUdate"); break; case 331: sprintf(name, "VarUdateFromDate"); break; case 332: sprintf(name, "GetAltMonthNames"); break; case 333: sprintf(name, "VarI8FromUI1"); break; case 334: sprintf(name, "VarI8FromI2"); break; case 335: sprintf(name, "VarI8FromR4"); break; case 336: sprintf(name, "VarI8FromR8"); break; case 337: sprintf(name, "VarI8FromCy"); break; case 338: sprintf(name, "VarI8FromDate"); break; case 339: sprintf(name, "VarI8FromStr"); break; case 340: sprintf(name, "VarI8FromDisp"); break; case 341: sprintf(name, "VarI8FromBool"); break; case 342: sprintf(name, "VarI8FromI1"); break; case 343: sprintf(name, "VarI8FromUI2"); break; case 344: sprintf(name, "VarI8FromUI4"); break; case 345: sprintf(name, "VarI8FromDec"); break; case 346: sprintf(name, "VarI2FromI8"); break; case 347: sprintf(name, "VarI2FromUI8"); break; case 348: sprintf(name, "VarI4FromI8"); break; case 349: sprintf(name, "VarI4FromUI8"); break; case 360: sprintf(name, "VarR4FromI8"); break; case 361: sprintf(name, "VarR4FromUI8"); break; case 362: sprintf(name, "VarR8FromI8"); break; case 363: sprintf(name, "VarR8FromUI8"); break; case 364: sprintf(name, "VarDateFromI8"); break; case 365: sprintf(name, "VarDateFromUI8"); break; case 366: sprintf(name, "VarCyFromI8"); break; case 367: sprintf(name, "VarCyFromUI8"); break; case 368: sprintf(name, "VarBstrFromI8"); break; case 369: sprintf(name, "VarBstrFromUI8"); break; case 370: sprintf(name, "VarBoolFromI8"); break; case 371: sprintf(name, "VarBoolFromUI8"); break; case 372: sprintf(name, "VarUI1FromI8"); break; case 373: sprintf(name, "VarUI1FromUI8"); break; case 374: sprintf(name, "VarDecFromI8"); break; case 375: sprintf(name, "VarDecFromUI8"); break; case 376: sprintf(name, "VarI1FromI8"); break; case 377: sprintf(name, "VarI1FromUI8"); break; case 378: sprintf(name, "VarUI2FromI8"); break; case 379: sprintf(name, "VarUI2FromUI8"); break; case 401: sprintf(name, "OleLoadPictureEx"); break; case 402: sprintf(name, "OleLoadPictureFileEx"); break; case 411: sprintf(name, "SafeArrayCreateVector"); break; case 412: sprintf(name, "SafeArrayCopyData"); break; case 413: sprintf(name, "VectorFromBstr"); break; case 414: sprintf(name, "BstrFromVector"); break; case 415: sprintf(name, "OleIconToCursor"); break; case 416: sprintf(name, "OleCreatePropertyFrameIndirect"); break; case 417: sprintf(name, "OleCreatePropertyFrame"); break; case 418: sprintf(name, "OleLoadPicture"); break; case 419: sprintf(name, "OleCreatePictureIndirect"); break; case 420: sprintf(name, "OleCreateFontIndirect"); break; case 421: sprintf(name, "OleTranslateColor"); break; case 422: sprintf(name, "OleLoadPictureFile"); break; case 423: sprintf(name, "OleSavePictureFile"); break; case 424: sprintf(name, "OleLoadPicturePath"); break; case 425: sprintf(name, "VarUI4FromI8"); break; case 426: sprintf(name, "VarUI4FromUI8"); break; case 427: sprintf(name, "VarI8FromUI8"); break; case 428: sprintf(name, "VarUI8FromI8"); break; case 429: sprintf(name, "VarUI8FromUI1"); break; case 430: sprintf(name, "VarUI8FromI2"); break; case 431: sprintf(name, "VarUI8FromR4"); break; case 432: sprintf(name, "VarUI8FromR8"); break; case 433: sprintf(name, "VarUI8FromCy"); break; case 434: sprintf(name, "VarUI8FromDate"); break; case 435: sprintf(name, "VarUI8FromStr"); break; case 436: sprintf(name, "VarUI8FromDisp"); break; case 437: sprintf(name, "VarUI8FromBool"); break; case 438: sprintf(name, "VarUI8FromI1"); break; case 439: sprintf(name, "VarUI8FromUI2"); break; case 440: sprintf(name, "VarUI8FromUI4"); break; case 441: sprintf(name, "VarUI8FromDec"); break; case 442: sprintf(name, "RegisterTypeLibForUser"); break; case 443: sprintf(name, "UnRegisterTypeLibForUser"); break; default: break; } } if (name[0] == '\0') sprintf(name, "ord%u", ord); return yr_strdup(name); } yara-4.5.3/libyara/modules/string/000077500000000000000000000000001501365277300170715ustar00rootroot00000000000000yara-4.5.3/libyara/modules/string/string.c000066400000000000000000000063151501365277300205500ustar00rootroot00000000000000/* Copyright (c) 2014-2022. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #define MODULE_NAME string bool string_to_int(char* s, int base, int64_t* result) { char* endp = s; errno = 0; *result = strtoll(s, &endp, base); if (errno != 0) { // Error while parsing the string. return false; } if (endp == s) { // No digits were found. return false; } if (*endp != '\0') { // Parsing did not reach the end of the string. return false; } return true; } define_function(to_int) { char* s = string_argument(1); int64_t result = 0; if (string_to_int(s, 0, &result)) { return_integer(result); } else { return_integer(YR_UNDEFINED); } } define_function(to_int_base) { char* s = string_argument(1); int64_t base = integer_argument(2); int64_t result = 0; if (!(base == 0 || (base >= 2 && base <= 36))) { return_integer(YR_UNDEFINED); } if (string_to_int(s, base, &result)) { return_integer(result); } else { return_integer(YR_UNDEFINED); } } define_function(string_length) { SIZED_STRING* s = sized_string_argument(1); return_integer(s->length); } begin_declarations declare_function("to_int", "s", "i", to_int); declare_function("to_int", "si", "i", to_int_base); declare_function("length", "s", "i", string_length); end_declarations int module_initialize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_finalize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { return ERROR_SUCCESS; } int module_unload(YR_OBJECT* module_object) { return ERROR_SUCCESS; } yara-4.5.3/libyara/modules/tests/000077500000000000000000000000001501365277300167255ustar00rootroot00000000000000yara-4.5.3/libyara/modules/tests/tests.c000066400000000000000000000135301501365277300202350ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #define MODULE_NAME tests define_function(fsum_2) { double a = float_argument(1); double b = float_argument(2); return_float(a + b); } define_function(fsum_3) { double a = float_argument(1); double b = float_argument(2); double c = float_argument(3); return_float(a + b + c); } define_function(isum_2) { int64_t a = integer_argument(1); int64_t b = integer_argument(2); return_integer(a + b); } define_function(isum_3) { int64_t a = integer_argument(1); int64_t b = integer_argument(2); int64_t c = integer_argument(3); return_integer(a + b + c); } define_function(length) { char* s = string_argument(1); return_integer(strlen(s)); } define_function(empty) { return_string(""); } define_function(match) { return_integer( yr_re_match(yr_scan_context(), regexp_argument(1), string_argument(2))); } define_function(foobar) { int64_t arg = integer_argument(1); switch (arg) { case 1: return_string("foo"); break; case 2: return_string("bar"); break; } return_string("oops") } begin_declarations begin_struct("constants") declare_integer("one"); declare_integer("two"); declare_string("foo"); declare_string("empty"); end_struct("constants") begin_struct("undefined") declare_integer("i"); declare_float("f"); end_struct("undefined") declare_string("module_data"); declare_integer_array("integer_array"); declare_string_array("string_array"); declare_integer_dictionary("integer_dict"); declare_string_dictionary("string_dict"); begin_struct_array("struct_array") declare_integer("i"); declare_string("s"); end_struct_array("struct_array") begin_struct_dictionary("struct_dict") declare_integer("i"); declare_string("s"); end_struct_dictionary("struct_dict"); begin_struct_dictionary("empty_struct_dict") declare_integer("unused"); end_struct_dictionary("empty_struct_dict") begin_struct_array("empty_struct_array") begin_struct_array("struct_array") declare_string("unused"); end_struct_array("struct_array"); begin_struct_dictionary("struct_dict") declare_string("unused"); end_struct_dictionary("struct_dict"); end_struct_array("empty_struct_array"); declare_function("match", "rs", "i", match); declare_function("isum", "ii", "i", isum_2); declare_function("isum", "iii", "i", isum_3); declare_function("fsum", "ff", "f", fsum_2); declare_function("fsum", "fff", "f", fsum_3); declare_function("length", "s", "i", length); declare_function("empty", "", "s", empty); declare_function("foobar", "i", "s", foobar); end_declarations int module_initialize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_finalize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { yr_set_integer(1, module_object, "constants.one"); yr_set_integer(2, module_object, "constants.two"); yr_set_string("foo", module_object, "constants.foo"); yr_set_string("", module_object, "constants.empty"); yr_set_integer(1, module_object, "struct_array[1].i"); yr_set_integer(0, module_object, "integer_array[%i]", 0); yr_set_integer(1, module_object, "integer_array[%i]", 1); yr_set_integer(2, module_object, "integer_array[%i]", 2); yr_set_integer(256, module_object, "integer_array[%i]", 256); yr_set_string("foo", module_object, "string_array[%i]", 0); yr_set_string("bar", module_object, "string_array[%i]", 1); yr_set_string("baz", module_object, "string_array[%i]", 2); yr_set_sized_string("foo\0bar", 7, module_object, "string_array[%i]", 3); yr_set_string("foo", module_object, "string_dict[%s]", "foo"); yr_set_string("bar", module_object, "string_dict[\"bar\"]"); yr_set_string("foo", module_object, "struct_dict[%s].s", "foo"); yr_set_integer(1, module_object, "struct_dict[%s].i", "foo"); if (module_data_size > 0 && module_data != NULL) { yr_set_sized_string( (const char*) module_data, module_data_size, module_object, "module_data"); } return ERROR_SUCCESS; } int module_unload(YR_OBJECT* module_object) { // Fail if module_unload is called twice with the same module_object if (module_object->data == (void*) 0xFABADA) assert(false); module_object->data = (void*) 0xFABADA; return ERROR_SUCCESS; } yara-4.5.3/libyara/modules/time/000077500000000000000000000000001501365277300165215ustar00rootroot00000000000000yara-4.5.3/libyara/modules/time/time.c000066400000000000000000000041561501365277300176310ustar00rootroot00000000000000/* Copyright (c) 2014-2017. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #define MODULE_NAME time define_function(now) { time_t now = time(NULL); if (now == -1) return_integer(YR_UNDEFINED); return_integer((long) now); } begin_declarations declare_function("now", "", "i", now); end_declarations; int module_initialize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_finalize(YR_MODULE* module) { return ERROR_SUCCESS; } int module_load( YR_SCAN_CONTEXT* context, YR_OBJECT* module_object, void* module_data, size_t module_data_size) { return ERROR_SUCCESS; } int module_unload(YR_OBJECT* module_object) { return ERROR_SUCCESS; } yara-4.5.3/libyara/notebook.c000066400000000000000000000143531501365277300161050ustar00rootroot00000000000000/* Copyright (c) 2020. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include // Forward declaration of YR_NOTEBOOK_PAGE. typedef struct YR_NOTEBOOK_PAGE YR_NOTEBOOK_PAGE; // A notebook is a data structure that can be used for allocating memory // space in the same way malloc() would do. However, the buffers returned // by yr_notebook_alloc() are backed by a larger buffer reserved by the notebook // beforehand called a "page". The notebook fulfills the allocations performed // via yr_notebook_alloc() with space taken from the current page, or creates // a new page when necessary. It's recommended that the page size is at least // 4x the size of the buffers you plan to allocate with yr_notebook_alloc(). // // Once the notebook is destroyed all the pages are freed, and consequently // all the buffers allocated via yr_notebook_alloc(). struct YR_NOTEBOOK { // The mininum size of each page in the notebook. size_t min_page_size; // Pointer to the first page in the book, this is also the most recently // created page, the one that is being filled. YR_NOTEBOOK_PAGE* page_list_head; }; struct YR_NOTEBOOK_PAGE { // Size of this page. size_t size; // Amount of bytes in the page that are actually used. size_t used; // Pointer to next page. YR_NOTEBOOK_PAGE* next; // Page's data. // // This field must be 8-byte aligned to guarantee that all notebooks // allocations are 8-byte aligned. YR_ALIGN(8) uint8_t data[0]; }; //////////////////////////////////////////////////////////////////////////////// // Creates a new notebook. The notebook initially has a single page of size // min_page_size, but more pages will be created as needed. // // Args: // min_page_size: The minimum size of each page in the notebook. // notebook: Address of a pointer to the newly created notebook. // // Returns: // ERROR_SUCCESS // ERROR_INSUFFICIENT_MEMORY // int yr_notebook_create(size_t min_page_size, YR_NOTEBOOK** notebook) { YR_NOTEBOOK* new_notebook = yr_malloc(sizeof(YR_NOTEBOOK)); if (new_notebook == NULL) return ERROR_INSUFFICIENT_MEMORY; new_notebook->page_list_head = yr_malloc( sizeof(YR_NOTEBOOK_PAGE) + min_page_size); if (new_notebook->page_list_head == NULL) { yr_free(new_notebook); return ERROR_INSUFFICIENT_MEMORY; } new_notebook->min_page_size = min_page_size; new_notebook->page_list_head->size = min_page_size; new_notebook->page_list_head->used = 0; new_notebook->page_list_head->next = NULL; *notebook = new_notebook; return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Destroys a notebook and frees all the notebook's pages. // // Args: // notebook: Pointer to the notebook being destroyed. // // Returns: // ERROR_SUCCESS // int yr_notebook_destroy(YR_NOTEBOOK* notebook) { YR_NOTEBOOK_PAGE* page = notebook->page_list_head; while (page != NULL) { YR_NOTEBOOK_PAGE* next = page->next; yr_free(page); page = next; } yr_free(notebook); return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Allocates a memory buffer from a notebook. The memory is freed when the // notebook is destroyed, allocated buffers can't be freed individually. The // returned buffer is guaranteed to be aligned to an 8-byte boundary. // // Args: // notebook: Pointer to the notebook. // size: Size of the allocated memory. // // Returns: // Pointer to the allocated memory, or NULL if the allocation fails. // void* yr_notebook_alloc(YR_NOTEBOOK* notebook, size_t size) { // Round up the size to a multiple of 8, which also implies that the returned // pointers are aligned to 8 bytes. The 8-byte alignment is required by some // platforms (e.g. ARM and Sparc) that have strict alignment requirements when // deferrencing pointers to types larger than a byte. size = (size + 7) & ~0x7; YR_NOTEBOOK_PAGE* current_page = notebook->page_list_head; // If the requested size doesn't fit in current page's free space, allocate // a new page. if (current_page->size - current_page->used < size) { size_t min_size = notebook->min_page_size; // The new page must be able to fit the requested buffer, so find the // multiple of notebook->min_page_size that is larger or equal than than // size. size_t page_size = (size / min_size) * min_size + min_size; YR_NOTEBOOK_PAGE* new_page = yr_malloc( sizeof(YR_NOTEBOOK_PAGE) + page_size); if (new_page == NULL) return NULL; new_page->size = page_size; new_page->used = 0; new_page->next = notebook->page_list_head; notebook->page_list_head = new_page; } void* ptr = notebook->page_list_head->data + notebook->page_list_head->used; notebook->page_list_head->used += size; return ptr; } yara-4.5.3/libyara/object.c000066400000000000000000000632641501365277300155400ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include //////////////////////////////////////////////////////////////////////////////// // Creates a new object with the given type and identifier. If a parent is // specified the new object is owned by the parent and it will be destroyed when // the parent is destroyed. You must not call yr_object_destroy on an objected // that has a parent, you should destroy the parent instead. // int yr_object_create( int8_t type, const char* identifier, YR_OBJECT* parent, YR_OBJECT** object) { YR_OBJECT* obj; size_t object_size = 0; assert(parent != NULL || object != NULL); assert(identifier != NULL); switch (type) { case OBJECT_TYPE_STRUCTURE: object_size = sizeof(YR_OBJECT_STRUCTURE); break; case OBJECT_TYPE_ARRAY: object_size = sizeof(YR_OBJECT_ARRAY); break; case OBJECT_TYPE_DICTIONARY: object_size = sizeof(YR_OBJECT_DICTIONARY); break; case OBJECT_TYPE_INTEGER: object_size = sizeof(YR_OBJECT); break; case OBJECT_TYPE_FLOAT: object_size = sizeof(YR_OBJECT); break; case OBJECT_TYPE_STRING: object_size = sizeof(YR_OBJECT); break; case OBJECT_TYPE_FUNCTION: object_size = sizeof(YR_OBJECT_FUNCTION); break; default: assert(false); } obj = (YR_OBJECT*) yr_malloc(object_size); if (obj == NULL) return ERROR_INSUFFICIENT_MEMORY; obj->type = type; obj->identifier = yr_strdup(identifier); obj->parent = parent; obj->data = NULL; switch (type) { case OBJECT_TYPE_INTEGER: obj->value.i = YR_UNDEFINED; break; case OBJECT_TYPE_FLOAT: obj->value.d = NAN; break; case OBJECT_TYPE_STRING: obj->value.ss = NULL; break; case OBJECT_TYPE_STRUCTURE: object_as_structure(obj)->members = NULL; break; case OBJECT_TYPE_ARRAY: object_as_array(obj)->items = NULL; object_as_array(obj)->prototype_item = NULL; break; case OBJECT_TYPE_DICTIONARY: object_as_dictionary(obj)->items = NULL; object_as_dictionary(obj)->prototype_item = NULL; break; case OBJECT_TYPE_FUNCTION: object_as_function(obj)->return_obj = NULL; for (int i = 0; i < YR_MAX_OVERLOADED_FUNCTIONS; i++) { object_as_function(obj)->prototypes[i].arguments_fmt = NULL; object_as_function(obj)->prototypes[i].code = NULL; } break; } if (obj->identifier == NULL) { yr_free(obj); return ERROR_INSUFFICIENT_MEMORY; } if (parent != NULL) { assert( parent->type == OBJECT_TYPE_STRUCTURE || parent->type == OBJECT_TYPE_ARRAY || parent->type == OBJECT_TYPE_DICTIONARY || parent->type == OBJECT_TYPE_FUNCTION); // Objects with a parent take the canary from it. obj->canary = parent->canary; switch (parent->type) { case OBJECT_TYPE_STRUCTURE: FAIL_ON_ERROR_WITH_CLEANUP(yr_object_structure_set_member(parent, obj), { yr_free((void*) obj->identifier); yr_free(obj); }); break; case OBJECT_TYPE_ARRAY: object_as_array(parent)->prototype_item = obj; break; case OBJECT_TYPE_DICTIONARY: object_as_dictionary(parent)->prototype_item = obj; break; case OBJECT_TYPE_FUNCTION: object_as_function(parent)->return_obj = obj; break; } } if (object != NULL) *object = obj; return ERROR_SUCCESS; } void yr_object_set_canary(YR_OBJECT* object, int canary) { object->canary = canary; } int yr_object_function_create( const char* identifier, const char* arguments_fmt, const char* return_fmt, YR_MODULE_FUNC code, YR_OBJECT* parent, YR_OBJECT** function) { YR_OBJECT* return_obj; YR_OBJECT* o = NULL; YR_OBJECT_FUNCTION* f = NULL; int8_t return_type; // The parent of a function must be a structure. assert(parent != NULL && parent->type == OBJECT_TYPE_STRUCTURE); switch (*return_fmt) { case 'i': return_type = OBJECT_TYPE_INTEGER; break; case 's': return_type = OBJECT_TYPE_STRING; break; case 'f': return_type = OBJECT_TYPE_FLOAT; break; default: return ERROR_INVALID_FORMAT; } // Try to find if the structure already has a function // with that name. In that case this is a function overload. f = object_as_function(yr_object_lookup_field(parent, identifier)); // Overloaded functions must have the same return type. if (f != NULL && return_type != f->return_obj->type) return ERROR_WRONG_RETURN_TYPE; if (f == NULL) // Function doesn't exist yet { FAIL_ON_ERROR( yr_object_create(OBJECT_TYPE_FUNCTION, identifier, parent, &o)); // In case of failure while creating return_obj we don't need to free the // previously created "o" object, as it is already associated with its // parent and will be destroyed when the parent is destroyed. FAIL_ON_ERROR(yr_object_create(return_type, "result", o, &return_obj)); f = object_as_function(o); } for (int i = 0; i < YR_MAX_OVERLOADED_FUNCTIONS; i++) { if (f->prototypes[i].arguments_fmt == NULL) { f->prototypes[i].arguments_fmt = arguments_fmt; f->prototypes[i].code = code; break; } } if (function != NULL) *function = (YR_OBJECT*) f; return ERROR_SUCCESS; } int yr_object_from_external_variable( YR_EXTERNAL_VARIABLE* external, YR_OBJECT** object) { YR_OBJECT* obj; int result; uint8_t obj_type = 0; switch (external->type) { case EXTERNAL_VARIABLE_TYPE_INTEGER: case EXTERNAL_VARIABLE_TYPE_BOOLEAN: obj_type = OBJECT_TYPE_INTEGER; break; case EXTERNAL_VARIABLE_TYPE_FLOAT: obj_type = OBJECT_TYPE_FLOAT; break; case EXTERNAL_VARIABLE_TYPE_STRING: case EXTERNAL_VARIABLE_TYPE_MALLOC_STRING: obj_type = OBJECT_TYPE_STRING; break; default: assert(false); } result = yr_object_create(obj_type, external->identifier, NULL, &obj); if (result == ERROR_SUCCESS) { switch (external->type) { case EXTERNAL_VARIABLE_TYPE_INTEGER: case EXTERNAL_VARIABLE_TYPE_BOOLEAN: result = yr_object_set_integer(external->value.i, obj, NULL); break; case EXTERNAL_VARIABLE_TYPE_FLOAT: result = yr_object_set_float(external->value.f, obj, NULL); break; case EXTERNAL_VARIABLE_TYPE_STRING: case EXTERNAL_VARIABLE_TYPE_MALLOC_STRING: result = yr_object_set_string( external->value.s, strlen(external->value.s), obj, NULL); break; } if (result == ERROR_SUCCESS) { *object = obj; } else { yr_object_destroy(obj); } } return result; } //////////////////////////////////////////////////////////////////////////////// // Destroy an objects, and any other object that is a child of it. For example, // destroying a struct will destroy all its members. // void yr_object_destroy(YR_OBJECT* object) { YR_STRUCTURE_MEMBER* member; YR_STRUCTURE_MEMBER* next_member; YR_ARRAY_ITEMS* array_items; YR_DICTIONARY_ITEMS* dict_items; if (object == NULL) return; switch (object->type) { case OBJECT_TYPE_STRUCTURE: member = object_as_structure(object)->members; while (member != NULL) { next_member = member->next; yr_object_destroy(member->object); yr_free(member); member = next_member; } break; case OBJECT_TYPE_STRING: if (object->value.ss != NULL) yr_free(object->value.ss); break; case OBJECT_TYPE_ARRAY: if (object_as_array(object)->prototype_item != NULL) yr_object_destroy(object_as_array(object)->prototype_item); array_items = object_as_array(object)->items; if (array_items != NULL) { for (int i = 0; i < array_items->length; i++) if (array_items->objects[i] != NULL) yr_object_destroy(array_items->objects[i]); } yr_free(array_items); break; case OBJECT_TYPE_DICTIONARY: if (object_as_dictionary(object)->prototype_item != NULL) yr_object_destroy(object_as_dictionary(object)->prototype_item); dict_items = object_as_dictionary(object)->items; if (dict_items != NULL) { for (int i = 0; i < dict_items->used; i++) { if (dict_items->objects[i].key != NULL) yr_free(dict_items->objects[i].key); if (dict_items->objects[i].obj != NULL) yr_object_destroy(dict_items->objects[i].obj); } } yr_free(dict_items); break; case OBJECT_TYPE_FUNCTION: yr_object_destroy(object_as_function(object)->return_obj); break; } yr_free((void*) object->identifier); yr_free(object); } YR_OBJECT* yr_object_lookup_field(YR_OBJECT* object, const char* field_name) { YR_STRUCTURE_MEMBER* member; assert(object != NULL); assert(object->type == OBJECT_TYPE_STRUCTURE); member = object_as_structure(object)->members; while (member != NULL) { if (strcmp(member->object->identifier, field_name) == 0) return member->object; member = member->next; } return NULL; } static YR_OBJECT* _yr_object_lookup( YR_OBJECT* object, int flags, const char* pattern, va_list args) { YR_OBJECT* obj = object; const char* p = pattern; const char* key = NULL; char str[256]; int i; int index = -1; while (obj != NULL) { i = 0; while (*p != '\0' && *p != '.' && *p != '[' && i < sizeof(str) - 1) { str[i++] = *p++; } str[i] = '\0'; if (obj->type != OBJECT_TYPE_STRUCTURE) return NULL; obj = yr_object_lookup_field(obj, str); if (obj == NULL) return NULL; if (*p == '[') { p++; if (*p == '%') { p++; switch (*p++) { case 'i': index = va_arg(args, int); break; case 's': key = va_arg(args, const char*); break; default: return NULL; } } else if (*p >= '0' && *p <= '9') { index = (int) strtol(p, (char**) &p, 10); } else if (*p == '"') { i = 0; p++; // skip the opening quotation mark while (*p != '"' && *p != '\0' && i < sizeof(str) - 1) str[i++] = *p++; str[i] = '\0'; p++; // skip the closing quotation mark key = str; } else { return NULL; } assert(*p == ']'); p++; assert(*p == '.' || *p == '\0'); switch (obj->type) { case OBJECT_TYPE_ARRAY: assert(index != -1); obj = yr_object_array_get_item(obj, flags, index); break; case OBJECT_TYPE_DICTIONARY: assert(key != NULL); obj = yr_object_dict_get_item(obj, flags, key); break; } } if (*p == '\0') break; p++; } return obj; } YR_OBJECT* yr_object_lookup( YR_OBJECT* object, int flags, const char* pattern, ...) { YR_OBJECT* result; va_list args; va_start(args, pattern); result = _yr_object_lookup(object, flags, pattern, args); va_end(args); return result; } int yr_object_copy(YR_OBJECT* object, YR_OBJECT** object_copy) { YR_OBJECT* copy; YR_OBJECT* o; YR_STRUCTURE_MEMBER* structure_member; *object_copy = NULL; FAIL_ON_ERROR( yr_object_create(object->type, object->identifier, NULL, ©)); copy->canary = object->canary; switch (object->type) { case OBJECT_TYPE_INTEGER: copy->value.i = object->value.i; break; case OBJECT_TYPE_FLOAT: copy->value.d = object->value.d; break; case OBJECT_TYPE_STRING: if (object->value.ss != NULL) copy->value.ss = ss_dup(object->value.ss); else copy->value.ss = NULL; break; case OBJECT_TYPE_FUNCTION: FAIL_ON_ERROR_WITH_CLEANUP( yr_object_copy( object_as_function(object)->return_obj, &object_as_function(copy)->return_obj), // cleanup yr_object_destroy(copy)); for (int i = 0; i < YR_MAX_OVERLOADED_FUNCTIONS; i++) object_as_function(copy)->prototypes[i] = object_as_function(object)->prototypes[i]; break; case OBJECT_TYPE_STRUCTURE: structure_member = object_as_structure(object)->members; while (structure_member != NULL) { FAIL_ON_ERROR_WITH_CLEANUP( yr_object_copy(structure_member->object, &o), yr_object_destroy(copy)); FAIL_ON_ERROR_WITH_CLEANUP(yr_object_structure_set_member(copy, o), // cleanup yr_free(o); yr_object_destroy(copy)); structure_member = structure_member->next; } break; case OBJECT_TYPE_ARRAY: FAIL_ON_ERROR_WITH_CLEANUP( yr_object_copy(object_as_array(object)->prototype_item, &o), yr_object_destroy(copy)); object_as_array(copy)->prototype_item = o; break; case OBJECT_TYPE_DICTIONARY: FAIL_ON_ERROR_WITH_CLEANUP( yr_object_copy(object_as_dictionary(object)->prototype_item, &o), yr_object_destroy(copy)); object_as_dictionary(copy)->prototype_item = o; break; default: assert(false); } *object_copy = copy; return ERROR_SUCCESS; } int yr_object_structure_set_member(YR_OBJECT* object, YR_OBJECT* member) { YR_STRUCTURE_MEMBER* sm; assert(object->type == OBJECT_TYPE_STRUCTURE); // Check if the object already have a member with the same identifier if (yr_object_lookup_field(object, member->identifier) != NULL) return ERROR_DUPLICATED_STRUCTURE_MEMBER; sm = (YR_STRUCTURE_MEMBER*) yr_malloc(sizeof(YR_STRUCTURE_MEMBER)); if (sm == NULL) return ERROR_INSUFFICIENT_MEMORY; member->parent = object; sm->object = member; sm->next = object_as_structure(object)->members; object_as_structure(object)->members = sm; return ERROR_SUCCESS; } YR_API int yr_object_array_length(YR_OBJECT* object) { YR_OBJECT_ARRAY* array; assert(object->type == OBJECT_TYPE_ARRAY); array = object_as_array(object); if (array->items == NULL) return 0; return array->items->length; } YR_API YR_OBJECT* yr_object_array_get_item(YR_OBJECT* object, int flags, int index) { YR_OBJECT* result = NULL; YR_OBJECT_ARRAY* array; assert(object->type == OBJECT_TYPE_ARRAY); if (index < 0) return NULL; array = object_as_array(object); if (array->items != NULL && array->items->capacity > index) result = array->items->objects[index]; if (result == NULL && flags & OBJECT_CREATE) { yr_object_copy(array->prototype_item, &result); if (result != NULL) yr_object_array_set_item(object, result, index); } return result; } int yr_object_array_set_item(YR_OBJECT* object, YR_OBJECT* item, int index) { YR_OBJECT_ARRAY* array; int capacity; assert(index >= 0); assert(object->type == OBJECT_TYPE_ARRAY); array = object_as_array(object); if (array->items == NULL) { capacity = 64; while (capacity <= index) capacity *= 2; array->items = (YR_ARRAY_ITEMS*) yr_malloc( sizeof(YR_ARRAY_ITEMS) + capacity * sizeof(YR_OBJECT*)); if (array->items == NULL) return ERROR_INSUFFICIENT_MEMORY; memset(array->items->objects, 0, capacity * sizeof(YR_OBJECT*)); array->items->capacity = capacity; array->items->length = 0; } else if (index >= array->items->capacity) { capacity = array->items->capacity * 2; while (capacity <= index) capacity *= 2; array->items = (YR_ARRAY_ITEMS*) yr_realloc( array->items, sizeof(YR_ARRAY_ITEMS) + capacity * sizeof(YR_OBJECT*)); if (array->items == NULL) return ERROR_INSUFFICIENT_MEMORY; for (int i = array->items->capacity; i < capacity; i++) array->items->objects[i] = NULL; array->items->capacity = capacity; } item->parent = object; array->items->objects[index] = item; if (index >= array->items->length) array->items->length = index + 1; return ERROR_SUCCESS; } YR_OBJECT* yr_object_dict_get_item( YR_OBJECT* object, int flags, const char* key) { YR_OBJECT* result = NULL; YR_OBJECT_DICTIONARY* dict; assert(object->type == OBJECT_TYPE_DICTIONARY); dict = object_as_dictionary(object); if (dict->items != NULL) { for (int i = 0; i < dict->items->used; i++) { if (strcmp(dict->items->objects[i].key->c_string, key) == 0) result = dict->items->objects[i].obj; } } if (result == NULL && flags & OBJECT_CREATE) { yr_object_copy(dict->prototype_item, &result); if (result != NULL) yr_object_dict_set_item(object, result, key); } return result; } int yr_object_dict_set_item(YR_OBJECT* object, YR_OBJECT* item, const char* key) { YR_OBJECT_DICTIONARY* dict; int count; assert(object->type == OBJECT_TYPE_DICTIONARY); dict = object_as_dictionary(object); if (dict->items == NULL) { count = 64; dict->items = (YR_DICTIONARY_ITEMS*) yr_malloc( sizeof(YR_DICTIONARY_ITEMS) + count * sizeof(dict->items->objects[0])); if (dict->items == NULL) return ERROR_INSUFFICIENT_MEMORY; memset(dict->items->objects, 0, count * sizeof(dict->items->objects[0])); dict->items->free = count; dict->items->used = 0; } else if (dict->items->free == 0) { count = dict->items->used * 2; dict->items = (YR_DICTIONARY_ITEMS*) yr_realloc( dict->items, sizeof(YR_DICTIONARY_ITEMS) + count * sizeof(dict->items->objects[0])); if (dict->items == NULL) return ERROR_INSUFFICIENT_MEMORY; for (int i = dict->items->used; i < count; i++) { dict->items->objects[i].key = NULL; dict->items->objects[i].obj = NULL; } dict->items->free = dict->items->used; } item->parent = object; dict->items->objects[dict->items->used].key = ss_new(key); dict->items->objects[dict->items->used].obj = item; dict->items->used++; dict->items->free--; return ERROR_SUCCESS; } bool yr_object_has_undefined_value(YR_OBJECT* object, const char* field, ...) { YR_OBJECT* field_obj; va_list args; va_start(args, field); if (field != NULL) field_obj = _yr_object_lookup(object, 0, field, args); else field_obj = object; va_end(args); if (field_obj == NULL) return true; switch (field_obj->type) { case OBJECT_TYPE_FLOAT: return yr_isnan(field_obj->value.d); case OBJECT_TYPE_STRING: return field_obj->value.ss == NULL; case OBJECT_TYPE_INTEGER: return field_obj->value.i == YR_UNDEFINED; } return false; } int64_t yr_object_get_integer(YR_OBJECT* object, const char* field, ...) { YR_OBJECT* integer_obj; va_list args; va_start(args, field); if (field != NULL) integer_obj = _yr_object_lookup(object, 0, field, args); else integer_obj = object; va_end(args); if (integer_obj == NULL) return YR_UNDEFINED; assertf( integer_obj->type == OBJECT_TYPE_INTEGER, "type of \"%s\" is not integer\n", field); return integer_obj->value.i; } double yr_object_get_float(YR_OBJECT* object, const char* field, ...) { YR_OBJECT* double_obj; va_list args; va_start(args, field); if (field != NULL) double_obj = _yr_object_lookup(object, 0, field, args); else double_obj = object; va_end(args); if (double_obj == NULL) return NAN; assertf( double_obj->type == OBJECT_TYPE_FLOAT, "type of \"%s\" is not double\n", field); return double_obj->value.d; } SIZED_STRING* yr_object_get_string(YR_OBJECT* object, const char* field, ...) { YR_OBJECT* string_obj; va_list args; va_start(args, field); if (field != NULL) string_obj = _yr_object_lookup(object, 0, field, args); else string_obj = object; va_end(args); if (string_obj == NULL) return NULL; assertf( string_obj->type == OBJECT_TYPE_STRING, "type of \"%s\" is not string\n", field); return string_obj->value.ss; } int yr_object_set_integer( int64_t value, YR_OBJECT* object, const char* field, ...) { YR_OBJECT* integer_obj; va_list args; va_start(args, field); if (field != NULL) integer_obj = _yr_object_lookup(object, OBJECT_CREATE, field, args); else integer_obj = object; va_end(args); if (integer_obj == NULL) { if (field != NULL) return ERROR_INSUFFICIENT_MEMORY; else return ERROR_INVALID_ARGUMENT; } assert(integer_obj->type == OBJECT_TYPE_INTEGER); integer_obj->value.i = value; return ERROR_SUCCESS; } int yr_object_set_float(double value, YR_OBJECT* object, const char* field, ...) { YR_OBJECT* double_obj; va_list args; va_start(args, field); if (field != NULL) double_obj = _yr_object_lookup(object, OBJECT_CREATE, field, args); else double_obj = object; va_end(args); if (double_obj == NULL) { if (field != NULL) return ERROR_INSUFFICIENT_MEMORY; else return ERROR_INVALID_ARGUMENT; } assert(double_obj->type == OBJECT_TYPE_FLOAT); double_obj->value.d = value; return ERROR_SUCCESS; } int yr_object_set_string( const char* value, size_t len, YR_OBJECT* object, const char* field, ...) { YR_OBJECT* string_obj; va_list args; va_start(args, field); if (field != NULL) string_obj = _yr_object_lookup(object, OBJECT_CREATE, field, args); else string_obj = object; va_end(args); if (string_obj == NULL) { if (field != NULL) return ERROR_INSUFFICIENT_MEMORY; else return ERROR_INVALID_ARGUMENT; } assert(string_obj->type == OBJECT_TYPE_STRING); if (string_obj->value.ss != NULL) yr_free(string_obj->value.ss); if (value != NULL) { string_obj->value.ss = (SIZED_STRING*) yr_malloc( len + sizeof(SIZED_STRING)); if (string_obj->value.ss == NULL) return ERROR_INSUFFICIENT_MEMORY; string_obj->value.ss->length = (uint32_t) len; string_obj->value.ss->flags = 0; memcpy(string_obj->value.ss->c_string, value, len); string_obj->value.ss->c_string[len] = '\0'; } else { string_obj->value.ss = NULL; } return ERROR_SUCCESS; } YR_OBJECT* yr_object_get_root(YR_OBJECT* object) { YR_OBJECT* o = object; while (o->parent != NULL) o = o->parent; return o; } YR_API void yr_object_print_data( YR_OBJECT* object, int indent, int print_identifier) { YR_DICTIONARY_ITEMS* dict_items; YR_STRUCTURE_MEMBER* member; char indent_spaces[32]; indent = yr_min(indent, sizeof(indent_spaces) - 1); memset(indent_spaces, '\t', indent); indent_spaces[indent] = '\0'; if (print_identifier && object->type != OBJECT_TYPE_FUNCTION) printf("%s%s", indent_spaces, object->identifier); switch (object->type) { case OBJECT_TYPE_FLOAT: if (object->value.i != YR_UNDEFINED) printf(" = %f", object->value.d); else printf(" = YR_UNDEFINED"); break; case OBJECT_TYPE_INTEGER: if (object->value.i != YR_UNDEFINED) printf(" = %" PRId64, object->value.i); else printf(" = YR_UNDEFINED"); break; case OBJECT_TYPE_STRING: if (object->value.ss != NULL) { printf(" = \""); for (size_t l = 0; l < object->value.ss->length; l++) { char c = object->value.ss->c_string[l]; if (isprint((unsigned char) c)) printf("%c", c); else printf("\\x%02x", (unsigned char) c); } printf("\""); } else { printf(" = YR_UNDEFINED"); } break; case OBJECT_TYPE_STRUCTURE: member = object_as_structure(object)->members; while (member != NULL) { if (member->object->type != OBJECT_TYPE_FUNCTION) { printf("\n"); yr_object_print_data(member->object, indent + 1, 1); } member = member->next; } break; case OBJECT_TYPE_ARRAY: for (int i = 0; i < yr_object_array_length(object); i++) { YR_OBJECT* o = yr_object_array_get_item(object, 0, i); if (o != NULL) { printf("\n%s\t[%d]", indent_spaces, i); yr_object_print_data(o, indent + 1, 0); } } break; case OBJECT_TYPE_DICTIONARY: dict_items = object_as_dictionary(object)->items; if (dict_items != NULL) { for (int i = 0; i < dict_items->used; i++) { printf("\n%s\t%s", indent_spaces, dict_items->objects[i].key->c_string); yr_object_print_data(dict_items->objects[i].obj, indent + 1, 0); } } break; } } yara-4.5.3/libyara/parser.c000066400000000000000000001220671501365277300155630ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define todigit(x) \ ((x) >= 'A' && (x) <= 'F') ? ((uint8_t) (x - 'A' + 10)) \ : ((uint8_t) (x - '0')) int yr_parser_emit( yyscan_t yyscanner, uint8_t instruction, YR_ARENA_REF* instruction_ref) { return yr_arena_write_data( yyget_extra(yyscanner)->arena, YR_CODE_SECTION, &instruction, sizeof(uint8_t), instruction_ref); } int yr_parser_emit_with_arg_double( yyscan_t yyscanner, uint8_t instruction, double argument, YR_ARENA_REF* instruction_ref, YR_ARENA_REF* argument_ref) { int result = yr_arena_write_data( yyget_extra(yyscanner)->arena, YR_CODE_SECTION, &instruction, sizeof(uint8_t), instruction_ref); if (result == ERROR_SUCCESS) result = yr_arena_write_data( yyget_extra(yyscanner)->arena, YR_CODE_SECTION, &argument, sizeof(double), argument_ref); return result; } int yr_parser_emit_with_arg_int32( yyscan_t yyscanner, uint8_t instruction, int32_t argument, YR_ARENA_REF* instruction_ref, YR_ARENA_REF* argument_ref) { int result = yr_arena_write_data( yyget_extra(yyscanner)->arena, YR_CODE_SECTION, &instruction, sizeof(uint8_t), instruction_ref); if (result == ERROR_SUCCESS) result = yr_arena_write_data( yyget_extra(yyscanner)->arena, YR_CODE_SECTION, &argument, sizeof(int32_t), argument_ref); return result; } int yr_parser_emit_with_arg( yyscan_t yyscanner, uint8_t instruction, int64_t argument, YR_ARENA_REF* instruction_ref, YR_ARENA_REF* argument_ref) { int result = yr_arena_write_data( yyget_extra(yyscanner)->arena, YR_CODE_SECTION, &instruction, sizeof(uint8_t), instruction_ref); if (result == ERROR_SUCCESS) result = yr_arena_write_data( yyget_extra(yyscanner)->arena, YR_CODE_SECTION, &argument, sizeof(int64_t), argument_ref); return result; } int yr_parser_emit_with_arg_reloc( yyscan_t yyscanner, uint8_t instruction, void* argument, YR_ARENA_REF* instruction_ref, YR_ARENA_REF* argument_ref) { YR_ARENA_REF ref = YR_ARENA_NULL_REF; DECLARE_REFERENCE(void*, ptr) arg; memset(&arg, 0, sizeof(arg)); arg.ptr = argument; int result = yr_arena_write_data( yyget_extra(yyscanner)->arena, YR_CODE_SECTION, &instruction, sizeof(uint8_t), instruction_ref); if (result == ERROR_SUCCESS) result = yr_arena_write_data( yyget_extra(yyscanner)->arena, YR_CODE_SECTION, &arg, sizeof(arg), &ref); if (result == ERROR_SUCCESS) result = yr_arena_make_ptr_relocatable( yyget_extra(yyscanner)->arena, YR_CODE_SECTION, ref.offset, EOL); if (argument_ref != NULL) *argument_ref = ref; return result; } int yr_parser_emit_pushes_for_strings( yyscan_t yyscanner, const char* identifier, int* count) { YR_COMPILER* compiler = yyget_extra(yyscanner); YR_RULE* current_rule = _yr_compiler_get_rule_by_idx( compiler, compiler->current_rule_idx); YR_STRING* string; const char* string_identifier; const char* target_identifier; int matching = 0; yr_rule_strings_foreach(current_rule, string) { // Don't generate pushes for strings chained to another one, we are // only interested in non-chained strings or the head of the chain. if (string->chained_to == NULL) { string_identifier = string->identifier; target_identifier = identifier; while (*target_identifier != '\0' && *string_identifier != '\0' && *target_identifier == *string_identifier) { target_identifier++; string_identifier++; } if ((*target_identifier == '\0' && *string_identifier == '\0') || *target_identifier == '*') { yr_parser_emit_with_arg_reloc(yyscanner, OP_PUSH, string, NULL, NULL); string->flags |= STRING_FLAGS_REFERENCED; string->flags &= ~STRING_FLAGS_FIXED_OFFSET; string->flags &= ~STRING_FLAGS_SINGLE_MATCH; matching++; } } } if (count != NULL) { *count = matching; } if (matching == 0) { yr_compiler_set_error_extra_info( compiler, identifier) return ERROR_UNDEFINED_STRING; } return ERROR_SUCCESS; } // Emit OP_PUSH_RULE instructions for all rules whose identifier has given // prefix. int yr_parser_emit_pushes_for_rules( yyscan_t yyscanner, const char* prefix, int* count) { YR_COMPILER* compiler = yyget_extra(yyscanner); // Make sure the compiler is parsing a rule assert(compiler->current_rule_idx != UINT32_MAX); YR_RULE* rule; int matching = 0; YR_NAMESPACE* ns = (YR_NAMESPACE*) yr_arena_get_ptr( compiler->arena, YR_NAMESPACES_TABLE, compiler->current_namespace_idx * sizeof(struct YR_NAMESPACE)); // Can't use yr_rules_foreach here as that requires the rules to have been // finalized (inserting a NULL rule at the end). This is done when // yr_compiler_get_rules() is called, which also inserts a HALT instruction // into the current position in the code arena. Obviously we aren't done // compiling the rules yet so inserting a HALT is a bad idea. To deal with // this I'm manually walking all the currently compiled rules (up to the // current rule index) and comparing identifiers to see if it is one we should // use. // // Further, we have to get compiler->current_rule_idx before we start because // if we emit an OP_PUSH_RULE rule = yr_arena_get_ptr(compiler->arena, YR_RULES_TABLE, 0); for (uint32_t i = 0; i <= compiler->current_rule_idx; i++) { // Is rule->identifier prefixed by prefix? if (strncmp(prefix, rule->identifier, strlen(prefix)) == 0) { uint32_t rule_idx = yr_hash_table_lookup_uint32( compiler->rules_table, rule->identifier, ns->name); if (rule_idx != UINT32_MAX) { FAIL_ON_ERROR(yr_parser_emit_with_arg( yyscanner, OP_PUSH_RULE, rule_idx, NULL, NULL)); matching++; } } rule++; } if (count != NULL) { *count = matching; } if (matching == 0) { yr_compiler_set_error_extra_info(compiler, prefix); return ERROR_UNDEFINED_IDENTIFIER; } return ERROR_SUCCESS; } int yr_parser_emit_push_const(yyscan_t yyscanner, uint64_t argument) { uint8_t opcode[9]; int opcode_len = 1; if (argument == YR_UNDEFINED) { opcode[0] = OP_PUSH_U; } else if (argument <= 0xff) { opcode[0] = OP_PUSH_8; opcode[1] = (uint8_t) argument; opcode_len += sizeof(uint8_t); } else if (argument <= 0xffff) { opcode[0] = OP_PUSH_16; uint16_t u = (uint16_t) argument; memcpy(opcode + 1, &u, sizeof(uint16_t)); opcode_len += sizeof(uint16_t); } else if (argument <= 0xffffffff) { opcode[0] = OP_PUSH_32; uint32_t u = (uint32_t) argument; memcpy(opcode + 1, &u, sizeof(uint32_t)); opcode_len += sizeof(uint32_t); } else { opcode[0] = OP_PUSH; memcpy(opcode + 1, &argument, sizeof(uint64_t)); opcode_len += sizeof(uint64_t); } return yr_arena_write_data( yyget_extra(yyscanner)->arena, YR_CODE_SECTION, opcode, opcode_len, NULL); } int yr_parser_check_types( YR_COMPILER* compiler, YR_OBJECT_FUNCTION* function, const char* actual_args_fmt) { int i; for (i = 0; i < YR_MAX_OVERLOADED_FUNCTIONS; i++) { if (function->prototypes[i].arguments_fmt == NULL) break; if (strcmp(function->prototypes[i].arguments_fmt, actual_args_fmt) == 0) return ERROR_SUCCESS; } yr_compiler_set_error_extra_info(compiler, function->identifier) return ERROR_WRONG_ARGUMENTS; } int yr_parser_lookup_string( yyscan_t yyscanner, const char* identifier, YR_STRING** string) { YR_COMPILER* compiler = yyget_extra(yyscanner); YR_RULE* current_rule = _yr_compiler_get_rule_by_idx( compiler, compiler->current_rule_idx); yr_rule_strings_foreach(current_rule, *string) { // If some string $a gets fragmented into multiple chained // strings, all those fragments have the same $a identifier // but we are interested in the heading fragment, which is // that with chained_to == NULL if ((*string)->chained_to == NULL && strcmp((*string)->identifier, identifier) == 0) { return ERROR_SUCCESS; } } yr_compiler_set_error_extra_info(compiler, identifier) * string = NULL; return ERROR_UNDEFINED_STRING; } //////////////////////////////////////////////////////////////////////////////// // Searches for a variable with the given identifier in the scope of the current // "for" loop. In case of nested "for" loops the identifier is searched starting // at the top-level loop and going down thorough the nested loops until the // current one. This is ok because inner loops can not re-define an identifier // already defined by an outer loop. // // If the variable is found, the return value is the position that the variable // occupies among all the currently defined variables. If the variable doesn't // exist the return value is -1. // // The function can receive a pointer to a YR_EXPRESSION that will populated // with information about the variable if found. This pointer can be NULL if // the caller is not interested in getting that information. // int yr_parser_lookup_loop_variable( yyscan_t yyscanner, const char* identifier, YR_EXPRESSION* expr) { YR_COMPILER* compiler = yyget_extra(yyscanner); int i, j; int var_offset = 0; for (i = 0; i <= compiler->loop_index; i++) { var_offset += compiler->loop[i].vars_internal_count; for (j = 0; j < compiler->loop[i].vars_count; j++) { if (compiler->loop[i].vars[j].identifier.ptr != NULL && strcmp(identifier, compiler->loop[i].vars[j].identifier.ptr) == 0) { if (expr != NULL) *expr = compiler->loop[i].vars[j]; return var_offset + j; } } var_offset += compiler->loop[i].vars_count; } return -1; } static int _yr_parser_write_string( const char* identifier, YR_MODIFIER modifier, YR_COMPILER* compiler, SIZED_STRING* str, RE_AST* re_ast, YR_ARENA_REF* string_ref, int* min_atom_quality, int* num_atom) { SIZED_STRING* literal_string; YR_ATOM_LIST_ITEM* atom; YR_ATOM_LIST_ITEM* atom_list = NULL; int c, result; int max_string_len; bool free_literal = false; FAIL_ON_ERROR(yr_arena_allocate_struct( compiler->arena, YR_STRINGS_TABLE, sizeof(YR_STRING), string_ref, offsetof(YR_STRING, identifier), offsetof(YR_STRING, string), offsetof(YR_STRING, chained_to), EOL)); YR_STRING* string = (YR_STRING*) yr_arena_ref_to_ptr( compiler->arena, string_ref); YR_ARENA_REF ref; FAIL_ON_ERROR(_yr_compiler_store_string(compiler, identifier, &ref)); string->identifier = (const char*) yr_arena_ref_to_ptr(compiler->arena, &ref); string->rule_idx = compiler->current_rule_idx; string->idx = compiler->current_string_idx; string->fixed_offset = YR_UNDEFINED; compiler->current_string_idx++; if (modifier.flags & STRING_FLAGS_HEXADECIMAL || modifier.flags & STRING_FLAGS_REGEXP || modifier.flags & STRING_FLAGS_BASE64 || modifier.flags & STRING_FLAGS_BASE64_WIDE) { literal_string = yr_re_ast_extract_literal(re_ast); if (literal_string != NULL) free_literal = true; } else { literal_string = str; } if (literal_string != NULL) { modifier.flags |= STRING_FLAGS_LITERAL; result = _yr_compiler_store_data( compiler, literal_string->c_string, literal_string->length + 1, // +1 to include terminating NULL &ref); if (result != ERROR_SUCCESS) goto cleanup; string->length = (uint32_t) literal_string->length; string->string = (uint8_t*) yr_arena_ref_to_ptr(compiler->arena, &ref); if (modifier.flags & STRING_FLAGS_WIDE) max_string_len = string->length * 2; else max_string_len = string->length; if (max_string_len <= YR_MAX_ATOM_LENGTH) modifier.flags |= STRING_FLAGS_FITS_IN_ATOM; result = yr_atoms_extract_from_string( &compiler->atoms_config, (uint8_t*) literal_string->c_string, (int32_t) literal_string->length, modifier, &atom_list, min_atom_quality); if (result != ERROR_SUCCESS) goto cleanup; } else { // Non-literal strings can't be marked as fixed offset because once we // find a string atom in the scanned data we don't know the offset where // the string should start, as the non-literal strings can contain // variable-length portions. modifier.flags &= ~STRING_FLAGS_FIXED_OFFSET; // Save the position where the RE forward code starts for later reference. yr_arena_off_t forward_code_start = yr_arena_get_current_offset( compiler->arena, YR_RE_CODE_SECTION); // Emit forwards code result = yr_re_ast_emit_code(re_ast, compiler->arena, false); if (result != ERROR_SUCCESS) goto cleanup; // Emit backwards code result = yr_re_ast_emit_code(re_ast, compiler->arena, true); if (result != ERROR_SUCCESS) goto cleanup; // Extract atoms from the regular expression. result = yr_atoms_extract_from_re( &compiler->atoms_config, re_ast, modifier, &atom_list, min_atom_quality); if (result != ERROR_SUCCESS) goto cleanup; // If no atom was extracted let's add a zero-length atom. if (atom_list == NULL) { atom_list = (YR_ATOM_LIST_ITEM*) yr_malloc(sizeof(YR_ATOM_LIST_ITEM)); if (atom_list == NULL) { result = ERROR_INSUFFICIENT_MEMORY; goto cleanup; } atom_list->atom.length = 0; atom_list->backtrack = 0; atom_list->backward_code_ref = YR_ARENA_NULL_REF; atom_list->next = NULL; yr_arena_ptr_to_ref( compiler->arena, yr_arena_get_ptr( compiler->arena, YR_RE_CODE_SECTION, forward_code_start), &(atom_list->forward_code_ref)); } } string->flags = modifier.flags; // Add the string to Aho-Corasick automaton. result = yr_ac_add_string( compiler->automaton, string, string->idx, atom_list, compiler->arena); if (result != ERROR_SUCCESS) goto cleanup; atom = atom_list; c = 0; while (atom != NULL) { atom = atom->next; c++; } (*num_atom) += c; cleanup: if (free_literal) yr_free(literal_string); if (atom_list != NULL) yr_atoms_list_destroy(atom_list); return result; } static int _yr_parser_check_string_modifiers( yyscan_t yyscanner, YR_MODIFIER modifier) { YR_COMPILER* compiler = yyget_extra(yyscanner); // xor and nocase together is not implemented. if (modifier.flags & STRING_FLAGS_XOR && modifier.flags & STRING_FLAGS_NO_CASE) { yr_compiler_set_error_extra_info( compiler, "invalid modifier combination: xor nocase"); return ERROR_INVALID_MODIFIER; } // base64 and nocase together is not implemented. if (modifier.flags & STRING_FLAGS_NO_CASE && (modifier.flags & STRING_FLAGS_BASE64 || modifier.flags & STRING_FLAGS_BASE64_WIDE)) { yr_compiler_set_error_extra_info( compiler, modifier.flags & STRING_FLAGS_BASE64 ? "invalid modifier combination: base64 nocase" : "invalid modifier combination: base64wide nocase"); return ERROR_INVALID_MODIFIER; } // base64 and fullword together is not implemented. if (modifier.flags & STRING_FLAGS_FULL_WORD && (modifier.flags & STRING_FLAGS_BASE64 || modifier.flags & STRING_FLAGS_BASE64_WIDE)) { yr_compiler_set_error_extra_info( compiler, modifier.flags & STRING_FLAGS_BASE64 ? "invalid modifier combination: base64 fullword" : "invalid modifier combination: base64wide fullword"); return ERROR_INVALID_MODIFIER; } // base64 and xor together is not implemented. if (modifier.flags & STRING_FLAGS_XOR && (modifier.flags & STRING_FLAGS_BASE64 || modifier.flags & STRING_FLAGS_BASE64_WIDE)) { yr_compiler_set_error_extra_info( compiler, modifier.flags & STRING_FLAGS_BASE64 ? "invalid modifier combination: base64 xor" : "invalid modifier combination: base64wide xor"); return ERROR_INVALID_MODIFIER; } return ERROR_SUCCESS; } int yr_parser_reduce_string_declaration( yyscan_t yyscanner, YR_MODIFIER modifier, const char* identifier, SIZED_STRING* str, YR_ARENA_REF* string_ref) { int result = ERROR_SUCCESS; int min_atom_quality = YR_MAX_ATOM_QUALITY; int atom_quality; char message[512]; int32_t min_gap = 0; int32_t max_gap = 0; YR_COMPILER* compiler = yyget_extra(yyscanner); RE_AST* re_ast = NULL; RE_AST* remainder_re_ast = NULL; RE_ERROR re_error; YR_RULE* current_rule = _yr_compiler_get_rule_by_idx( compiler, compiler->current_rule_idx); // Determine if a string with the same identifier was already defined // by searching for the identifier in strings_table. uint32_t string_idx = yr_hash_table_lookup_uint32( compiler->strings_table, identifier, NULL); // The string was already defined, return an error. if (string_idx != UINT32_MAX) { yr_compiler_set_error_extra_info(compiler, identifier); return ERROR_DUPLICATED_STRING_IDENTIFIER; } // Empty strings are not allowed. if (str->length == 0) { yr_compiler_set_error_extra_info(compiler, identifier); return ERROR_EMPTY_STRING; } if (str->flags & SIZED_STRING_FLAGS_NO_CASE) modifier.flags |= STRING_FLAGS_NO_CASE; if (str->flags & SIZED_STRING_FLAGS_DOT_ALL) modifier.flags |= STRING_FLAGS_DOT_ALL; // Hex strings are always handled as DOT_ALL regexps. if (modifier.flags & STRING_FLAGS_HEXADECIMAL) modifier.flags |= STRING_FLAGS_DOT_ALL; if (!(modifier.flags & STRING_FLAGS_WIDE) && !(modifier.flags & STRING_FLAGS_BASE64 || modifier.flags & STRING_FLAGS_BASE64_WIDE)) { modifier.flags |= STRING_FLAGS_ASCII; } // The STRING_FLAGS_SINGLE_MATCH flag indicates that finding // a single match for the string is enough. This is true in // most cases, except when the string count (#) and string offset (@) // operators are used. All strings are marked STRING_FLAGS_SINGLE_MATCH // initially, and unmarked later if required. modifier.flags |= STRING_FLAGS_SINGLE_MATCH; // The STRING_FLAGS_FIXED_OFFSET indicates that the string doesn't // need to be searched all over the file because the user is using the // "at" operator. The string must be searched at a fixed offset in the // file. All strings are marked STRING_FLAGS_FIXED_OFFSET initially, // and unmarked later if required. modifier.flags |= STRING_FLAGS_FIXED_OFFSET; // If string identifier is $ this is an anonymous string, if not add the // identifier to strings_table. if (strcmp(identifier, "$") == 0) { modifier.flags |= STRING_FLAGS_ANONYMOUS; } else { FAIL_ON_ERROR(yr_hash_table_add_uint32( compiler->strings_table, identifier, NULL, compiler->current_string_idx)); } // Make sure that the the string does not have an invalid combination of // modifiers. FAIL_ON_ERROR(_yr_parser_check_string_modifiers(yyscanner, modifier)); if (modifier.flags & STRING_FLAGS_HEXADECIMAL || modifier.flags & STRING_FLAGS_REGEXP || modifier.flags & STRING_FLAGS_BASE64 || modifier.flags & STRING_FLAGS_BASE64_WIDE) { if (modifier.flags & STRING_FLAGS_HEXADECIMAL) result = yr_re_parse_hex(str->c_string, &re_ast, &re_error); else if (modifier.flags & STRING_FLAGS_REGEXP) { int flags = RE_PARSER_FLAG_NONE; if (compiler->strict_escape) flags |= RE_PARSER_FLAG_ENABLE_STRICT_ESCAPE_SEQUENCES; result = yr_re_parse(str->c_string, &re_ast, &re_error, flags); } else result = yr_base64_ast_from_string(str, modifier, &re_ast, &re_error); if (result != ERROR_SUCCESS) { if (result == ERROR_UNKNOWN_ESCAPE_SEQUENCE) { yywarning(yyscanner, "unknown escape sequence"); } else { snprintf( message, sizeof(message), "invalid %s \"%s\": %s", (modifier.flags & STRING_FLAGS_HEXADECIMAL) ? "hex string" : "regular expression", identifier, re_error.message); yr_compiler_set_error_extra_info(compiler, message); goto _exit; } } if (re_ast->flags & RE_FLAGS_FAST_REGEXP) modifier.flags |= STRING_FLAGS_FAST_REGEXP; if (re_ast->flags & RE_FLAGS_GREEDY) modifier.flags |= STRING_FLAGS_GREEDY_REGEXP; // Regular expressions in the strings section can't mix greedy and // ungreedy quantifiers like .* and .*?. That's because these regular // expressions can be matched forwards and/or backwards depending on the // atom found, and we need the regexp to be all-greedy or all-ungreedy to // be able to properly calculate the length of the match. if ((re_ast->flags & RE_FLAGS_GREEDY) && (re_ast->flags & RE_FLAGS_UNGREEDY)) { result = ERROR_INVALID_REGULAR_EXPRESSION; yr_compiler_set_error_extra_info( compiler, "greedy and ungreedy quantifiers can't be mixed in a regular " "expression"); goto _exit; } if (yr_re_ast_has_unbounded_quantifier_for_dot(re_ast)) { yywarning( yyscanner, "%s contains .*, .+ or .{x,} consider using .{,N}, .{1,N} or {x,N} " "with a reasonable value for N", identifier); } if (compiler->re_ast_callback != NULL) { compiler->re_ast_callback( current_rule, identifier, re_ast, compiler->re_ast_clbk_user_data); } *string_ref = YR_ARENA_NULL_REF; while (re_ast != NULL) { YR_ARENA_REF ref; uint32_t prev_string_idx = compiler->current_string_idx - 1; int32_t prev_min_gap = min_gap; int32_t prev_max_gap = max_gap; result = yr_re_ast_split_at_chaining_point( re_ast, &remainder_re_ast, &min_gap, &max_gap); if (result != ERROR_SUCCESS) goto _exit; result = _yr_parser_write_string( identifier, modifier, compiler, NULL, re_ast, &ref, &atom_quality, ¤t_rule->num_atoms); if (result != ERROR_SUCCESS) goto _exit; if (atom_quality < min_atom_quality) min_atom_quality = atom_quality; if (YR_ARENA_IS_NULL_REF(*string_ref)) { // This is the first string in the chain, the string reference // returned by this function must point to this string. *string_ref = ref; } else { // This is not the first string in the chain, set the appropriate // flags and fill the chained_to, chain_gap_min and chain_gap_max // fields. YR_STRING* prev_string = (YR_STRING*) yr_arena_get_ptr( compiler->arena, YR_STRINGS_TABLE, prev_string_idx * sizeof(YR_STRING)); YR_STRING* new_string = (YR_STRING*) yr_arena_ref_to_ptr( compiler->arena, &ref); new_string->chained_to = prev_string; new_string->chain_gap_min = prev_min_gap; new_string->chain_gap_max = prev_max_gap; // A string chained to another one can't have a fixed offset, only the // head of the string chain can have a fixed offset. new_string->flags &= ~STRING_FLAGS_FIXED_OFFSET; // There is a previous string, but that string wasn't marked as part // of a chain because we can't do that until knowing there will be // another string, let's flag it now the we know. prev_string->flags |= STRING_FLAGS_CHAIN_PART; // There is a previous string, so this string is part of a chain, but // there will be no more strings because there are no more AST to // split, which means that this is the chain's tail. if (remainder_re_ast == NULL) new_string->flags |= STRING_FLAGS_CHAIN_PART | STRING_FLAGS_CHAIN_TAIL; } yr_re_ast_destroy(re_ast); re_ast = remainder_re_ast; } } else // not a STRING_FLAGS_HEXADECIMAL or STRING_FLAGS_REGEXP or // STRING_FLAGS_BASE64 or STRING_FLAGS_BASE64_WIDE { result = _yr_parser_write_string( identifier, modifier, compiler, str, NULL, string_ref, &min_atom_quality, ¤t_rule->num_atoms); if (result != ERROR_SUCCESS) goto _exit; } if (min_atom_quality < compiler->atoms_config.quality_warning_threshold) { yywarning(yyscanner, "string \"%s\" may slow down scanning", identifier); } _exit: if (re_ast != NULL) yr_re_ast_destroy(re_ast); if (remainder_re_ast != NULL) yr_re_ast_destroy(remainder_re_ast); return result; } static int wildcard_iterator( void* prefix, size_t prefix_len, void* _value, void* data) { const char* identifier = (const char*) data; // If the identifier is prefixed by prefix, then it matches the wildcard. if (!strncmp(prefix, identifier, prefix_len)) return ERROR_IDENTIFIER_MATCHES_WILDCARD; return ERROR_SUCCESS; } int yr_parser_reduce_rule_declaration_phase_1( yyscan_t yyscanner, int32_t flags, const char* identifier, YR_ARENA_REF* rule_ref) { int result; YR_FIXUP* fixup; YR_COMPILER* compiler = yyget_extra(yyscanner); YR_NAMESPACE* ns = (YR_NAMESPACE*) yr_arena_get_ptr( compiler->arena, YR_NAMESPACES_TABLE, compiler->current_namespace_idx * sizeof(struct YR_NAMESPACE)); if (yr_hash_table_lookup_uint32( compiler->rules_table, identifier, ns->name) != UINT32_MAX || yr_hash_table_lookup(compiler->objects_table, identifier, NULL) != NULL) { // A rule or variable with the same identifier already exists, return the // appropriate error. yr_compiler_set_error_extra_info(compiler, identifier); return ERROR_DUPLICATED_IDENTIFIER; } // Iterate over all identifiers in wildcard_identifiers_table, and check if // any of them are a prefix of the identifier being declared. If so, return // ERROR_IDENTIFIER_MATCHES_WILDCARD. result = yr_hash_table_iterate( compiler->wildcard_identifiers_table, ns->name, wildcard_iterator, (void*) identifier); if (result == ERROR_IDENTIFIER_MATCHES_WILDCARD) { // This rule matches an existing wildcard rule set. yr_compiler_set_error_extra_info(compiler, identifier); } FAIL_ON_ERROR(result); FAIL_ON_ERROR(yr_arena_allocate_struct( compiler->arena, YR_RULES_TABLE, sizeof(YR_RULE), rule_ref, offsetof(YR_RULE, identifier), offsetof(YR_RULE, tags), offsetof(YR_RULE, strings), offsetof(YR_RULE, metas), offsetof(YR_RULE, ns), EOL)); YR_RULE* rule = (YR_RULE*) yr_arena_ref_to_ptr(compiler->arena, rule_ref); YR_ARENA_REF ref; FAIL_ON_ERROR(_yr_compiler_store_string(compiler, identifier, &ref)); rule->identifier = (const char*) yr_arena_ref_to_ptr(compiler->arena, &ref); rule->flags = flags; rule->ns = ns; rule->num_atoms = 0; YR_ARENA_REF jmp_offset_ref; // We are starting to parse a new rule, set current_rule_idx accordingly. compiler->current_rule_idx = compiler->next_rule_idx; compiler->next_rule_idx++; // The OP_INIT_RULE instruction behaves like a jump. When the rule is // disabled it skips over the rule's code and go straight to the next rule's // code. The jmp_offset_ref variable points to the jump's offset. The offset // is set to 0 as we don't know the jump target yet. When we finish // generating the rule's code in yr_parser_reduce_rule_declaration_phase_2 // the jump offset is set to its final value. FAIL_ON_ERROR(yr_parser_emit_with_arg_int32( yyscanner, OP_INIT_RULE, 0, NULL, &jmp_offset_ref)); FAIL_ON_ERROR(yr_arena_write_data( compiler->arena, YR_CODE_SECTION, &compiler->current_rule_idx, sizeof(compiler->current_rule_idx), NULL)); // Create a fixup entry for the jump and push it in the stack fixup = (YR_FIXUP*) yr_malloc(sizeof(YR_FIXUP)); if (fixup == NULL) return ERROR_INSUFFICIENT_MEMORY; fixup->ref = jmp_offset_ref; fixup->next = compiler->fixup_stack_head; compiler->fixup_stack_head = fixup; // Clean strings_table as we are starting to parse a new rule. yr_hash_table_clean(compiler->strings_table, NULL); FAIL_ON_ERROR(yr_hash_table_add_uint32( compiler->rules_table, identifier, ns->name, compiler->current_rule_idx)); return ERROR_SUCCESS; } int yr_parser_reduce_rule_declaration_phase_2( yyscan_t yyscanner, YR_ARENA_REF* rule_ref) { uint32_t max_strings_per_rule; uint32_t strings_in_rule = 0; YR_FIXUP* fixup; YR_STRING* string; YR_COMPILER* compiler = yyget_extra(yyscanner); yr_get_configuration_uint32( YR_CONFIG_MAX_STRINGS_PER_RULE, &max_strings_per_rule); YR_RULE* rule = (YR_RULE*) yr_arena_ref_to_ptr(compiler->arena, rule_ref); // Show warning if the rule is generating too many atoms. The warning is // shown if the number of atoms is greater than 20 times the maximum number // of strings allowed for a rule, as 20 is minimum number of atoms generated // for a string using *nocase*, *ascii* and *wide* modifiers simultaneously. if (rule->num_atoms > YR_ATOMS_PER_RULE_WARNING_THRESHOLD) { yywarning(yyscanner, "rule is slowing down scanning"); } yr_rule_strings_foreach(rule, string) { // Only the heading fragment in a chain of strings (the one with // chained_to == NULL) must be referenced. All other fragments // are never marked as referenced. // // Any string identifier that starts with '_' can be unreferenced. Anonymous // strings must always be referenced. if (!STRING_IS_REFERENCED(string) && string->chained_to == NULL && (STRING_IS_ANONYMOUS(string) || (!STRING_IS_ANONYMOUS(string) && string->identifier[1] != '_'))) { yr_compiler_set_error_extra_info( compiler, string->identifier) return ERROR_UNREFERENCED_STRING; } // If a string is unreferenced we need to unset the FIXED_OFFSET flag so // that it will match anywhere. if (!STRING_IS_REFERENCED(string) && string->chained_to == NULL && STRING_IS_FIXED_OFFSET(string)) { string->flags &= ~STRING_FLAGS_FIXED_OFFSET; } strings_in_rule++; if (strings_in_rule > max_strings_per_rule) { yr_compiler_set_error_extra_info( compiler, rule->identifier) return ERROR_TOO_MANY_STRINGS; } } FAIL_ON_ERROR(yr_parser_emit_with_arg( yyscanner, OP_MATCH_RULE, compiler->current_rule_idx, NULL, NULL)); fixup = compiler->fixup_stack_head; int32_t* jmp_offset_addr = (int32_t*) yr_arena_ref_to_ptr( compiler->arena, &fixup->ref); int32_t jmp_offset = yr_arena_get_current_offset( compiler->arena, YR_CODE_SECTION) - fixup->ref.offset + 1; memcpy(jmp_offset_addr, &jmp_offset, sizeof(jmp_offset)); // Remove fixup from the stack. compiler->fixup_stack_head = fixup->next; yr_free(fixup); // We have finished parsing the current rule set current_rule_idx to // UINT32_MAX indicating that we are not currently parsing a rule. compiler->current_rule_idx = UINT32_MAX; return ERROR_SUCCESS; } int yr_parser_reduce_string_identifier( yyscan_t yyscanner, const char* identifier, uint8_t instruction, uint64_t at_offset) { YR_STRING* string; YR_COMPILER* compiler = yyget_extra(yyscanner); if (strcmp(identifier, "$") == 0) // is an anonymous string ? { if (compiler->loop_for_of_var_index >= 0) // inside a loop ? { yr_parser_emit_with_arg( yyscanner, OP_PUSH_M, compiler->loop_for_of_var_index, NULL, NULL); yr_parser_emit(yyscanner, instruction, NULL); YR_RULE* current_rule = _yr_compiler_get_rule_by_idx( compiler, compiler->current_rule_idx); yr_rule_strings_foreach(current_rule, string) { if (instruction != OP_FOUND) string->flags &= ~STRING_FLAGS_SINGLE_MATCH; if (instruction == OP_FOUND_AT) { // Avoid overwriting any previous fixed offset if (string->fixed_offset == YR_UNDEFINED) string->fixed_offset = at_offset; // If a previous fixed offset was different, disable // the STRING_GFLAGS_FIXED_OFFSET flag because we only // have room to store a single fixed offset value if (string->fixed_offset != at_offset) string->flags &= ~STRING_FLAGS_FIXED_OFFSET; } else { string->flags &= ~STRING_FLAGS_FIXED_OFFSET; } } } else { // Anonymous strings not allowed outside of a loop return ERROR_MISPLACED_ANONYMOUS_STRING; } } else { FAIL_ON_ERROR(yr_parser_lookup_string(yyscanner, identifier, &string)); FAIL_ON_ERROR( yr_parser_emit_with_arg_reloc(yyscanner, OP_PUSH, string, NULL, NULL)); if (instruction != OP_FOUND) string->flags &= ~STRING_FLAGS_SINGLE_MATCH; if (instruction == OP_FOUND_AT) { // Avoid overwriting any previous fixed offset if (string->fixed_offset == YR_UNDEFINED) string->fixed_offset = at_offset; // If a previous fixed offset was different, disable // the STRING_GFLAGS_FIXED_OFFSET flag because we only // have room to store a single fixed offset value if (string->fixed_offset == YR_UNDEFINED || string->fixed_offset != at_offset) { string->flags &= ~STRING_FLAGS_FIXED_OFFSET; } } else { string->flags &= ~STRING_FLAGS_FIXED_OFFSET; } FAIL_ON_ERROR(yr_parser_emit(yyscanner, instruction, NULL)); string->flags |= STRING_FLAGS_REFERENCED; } return ERROR_SUCCESS; } int yr_parser_reduce_meta_declaration( yyscan_t yyscanner, int32_t type, const char* identifier, const char* string, int64_t integer, YR_ARENA_REF* meta_ref) { YR_ARENA_REF ref; YR_COMPILER* compiler = yyget_extra(yyscanner); FAIL_ON_ERROR(yr_arena_allocate_struct( compiler->arena, YR_METAS_TABLE, sizeof(YR_META), meta_ref, offsetof(YR_META, identifier), offsetof(YR_META, string), EOL)); YR_META* meta = (YR_META*) yr_arena_ref_to_ptr(compiler->arena, meta_ref); meta->type = type; meta->integer = integer; FAIL_ON_ERROR(_yr_compiler_store_string(compiler, identifier, &ref)); meta->identifier = (const char*) yr_arena_ref_to_ptr(compiler->arena, &ref); if (string != NULL) { FAIL_ON_ERROR(_yr_compiler_store_string(compiler, string, &ref)); meta->string = (const char*) yr_arena_ref_to_ptr(compiler->arena, &ref); } else { meta->string = NULL; } compiler->current_meta_idx++; return ERROR_SUCCESS; } static int _yr_parser_valid_module_name(SIZED_STRING* module_name) { if (module_name->length == 0) return false; if (strlen(module_name->c_string) != module_name->length) return false; return true; } int yr_parser_reduce_import(yyscan_t yyscanner, SIZED_STRING* module_name) { int result; YR_ARENA_REF ref; YR_COMPILER* compiler = yyget_extra(yyscanner); YR_OBJECT* module_structure; if (!_yr_parser_valid_module_name(module_name)) { yr_compiler_set_error_extra_info(compiler, module_name->c_string); return ERROR_INVALID_MODULE_NAME; } YR_NAMESPACE* ns = (YR_NAMESPACE*) yr_arena_get_ptr( compiler->arena, YR_NAMESPACES_TABLE, compiler->current_namespace_idx * sizeof(struct YR_NAMESPACE)); module_structure = (YR_OBJECT*) yr_hash_table_lookup( compiler->objects_table, module_name->c_string, ns->name); // if module already imported, do nothing if (module_structure != NULL) return ERROR_SUCCESS; FAIL_ON_ERROR(yr_object_create( OBJECT_TYPE_STRUCTURE, module_name->c_string, NULL, &module_structure)); FAIL_ON_ERROR(yr_hash_table_add( compiler->objects_table, module_name->c_string, ns->name, module_structure)); result = yr_modules_do_declarations(module_name->c_string, module_structure); if (result == ERROR_UNKNOWN_MODULE) yr_compiler_set_error_extra_info(compiler, module_name->c_string); if (result != ERROR_SUCCESS) return result; FAIL_ON_ERROR( _yr_compiler_store_string(compiler, module_name->c_string, &ref)); FAIL_ON_ERROR(yr_parser_emit_with_arg_reloc( yyscanner, OP_IMPORT, yr_arena_ref_to_ptr(compiler->arena, &ref), NULL, NULL)); return ERROR_SUCCESS; } static int _yr_parser_operator_to_opcode(const char* op, int expression_type) { int opcode = 0; switch (expression_type) { case EXPRESSION_TYPE_INTEGER: opcode = OP_INT_BEGIN; break; case EXPRESSION_TYPE_FLOAT: opcode = OP_DBL_BEGIN; break; case EXPRESSION_TYPE_STRING: opcode = OP_STR_BEGIN; break; default: assert(false); } if (op[0] == '<') { if (op[1] == '=') opcode += _OP_LE; else opcode += _OP_LT; } else if (op[0] == '>') { if (op[1] == '=') opcode += _OP_GE; else opcode += _OP_GT; } else if (op[1] == '=') { if (op[0] == '=') opcode += _OP_EQ; else opcode += _OP_NEQ; } else if (op[0] == '+') { opcode += _OP_ADD; } else if (op[0] == '-') { opcode += _OP_SUB; } else if (op[0] == '*') { opcode += _OP_MUL; } else if (op[0] == '\\') { opcode += _OP_DIV; } if (IS_INT_OP(opcode) || IS_DBL_OP(opcode) || IS_STR_OP(opcode)) { return opcode; } return OP_ERROR; } int yr_parser_reduce_operation( yyscan_t yyscanner, const char* op, YR_EXPRESSION left_operand, YR_EXPRESSION right_operand) { int expression_type; YR_COMPILER* compiler = yyget_extra(yyscanner); if ((left_operand.type == EXPRESSION_TYPE_INTEGER || left_operand.type == EXPRESSION_TYPE_FLOAT) && (right_operand.type == EXPRESSION_TYPE_INTEGER || right_operand.type == EXPRESSION_TYPE_FLOAT)) { if (left_operand.type != right_operand.type) { // One operand is double and the other is integer, // cast the integer to double FAIL_ON_ERROR(yr_parser_emit_with_arg( yyscanner, OP_INT_TO_DBL, (left_operand.type == EXPRESSION_TYPE_INTEGER) ? 2 : 1, NULL, NULL)); } expression_type = EXPRESSION_TYPE_FLOAT; if (left_operand.type == EXPRESSION_TYPE_INTEGER && right_operand.type == EXPRESSION_TYPE_INTEGER) { expression_type = EXPRESSION_TYPE_INTEGER; } FAIL_ON_ERROR(yr_parser_emit( yyscanner, _yr_parser_operator_to_opcode(op, expression_type), NULL)); } else if ( left_operand.type == EXPRESSION_TYPE_STRING && right_operand.type == EXPRESSION_TYPE_STRING) { int opcode = _yr_parser_operator_to_opcode(op, EXPRESSION_TYPE_STRING); if (opcode != OP_ERROR) { FAIL_ON_ERROR(yr_parser_emit(yyscanner, opcode, NULL)); } else { yr_compiler_set_error_extra_info_fmt( compiler, "strings don't support \"%s\" operation", op); return ERROR_WRONG_TYPE; } } else { yr_compiler_set_error_extra_info(compiler, "type mismatch"); return ERROR_WRONG_TYPE; } return ERROR_SUCCESS; } yara-4.5.3/libyara/pb/000077500000000000000000000000001501365277300145145ustar00rootroot00000000000000yara-4.5.3/libyara/pb/yara.proto000066400000000000000000000011621501365277300165350ustar00rootroot00000000000000syntax = "proto3"; package yara; import "google/protobuf/descriptor.proto"; message ModuleOptions { string name = 1; string root_message = 2; } message FieldOptions { string name = 1; bool ignore = 2; } message MessageOptions { string name = 1; } message EnumOptions { string name = 1; } extend google.protobuf.FileOptions { ModuleOptions module_options = 51503; } extend google.protobuf.FieldOptions { FieldOptions field_options = 51504; } extend google.protobuf.MessageOptions { MessageOptions message_options = 51505; } extend google.protobuf.EnumOptions { EnumOptions enum_options = 51506; } yara-4.5.3/libyara/proc.c000066400000000000000000000066041501365277300152300ustar00rootroot00000000000000/* Copyright (c) 2007-2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include int _yr_process_attach(int, YR_PROC_ITERATOR_CTX*); int _yr_process_detach(YR_PROC_ITERATOR_CTX*); YR_API int yr_process_open_iterator(int pid, YR_MEMORY_BLOCK_ITERATOR* iterator) { YR_DEBUG_FPRINTF(2, stderr, "+ %s(pid=%d) {\n", __FUNCTION__, pid); int result = ERROR_INTERNAL_FATAL_ERROR; YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) yr_malloc( sizeof(YR_PROC_ITERATOR_CTX)); if (context == NULL) { result = ERROR_INSUFFICIENT_MEMORY; goto _exit; } iterator->context = context; iterator->first = yr_process_get_first_memory_block; iterator->next = yr_process_get_next_memory_block; iterator->last_error = ERROR_SUCCESS; // In a process scan file size is undefined, when the file_size function is // set to NULL the value returned by the filesize keyword is YR_UNDEFINED. iterator->file_size = NULL; context->buffer = NULL; context->buffer_size = 0; context->current_block.base = 0; context->current_block.size = 0; context->current_block.context = context; context->current_block.fetch_data = yr_process_fetch_memory_block_data; context->proc_info = NULL; GOTO_EXIT_ON_ERROR_WITH_CLEANUP( _yr_process_attach(pid, context), yr_free(context)); result = ERROR_SUCCESS; _exit: YR_DEBUG_FPRINTF(2, stderr, "} = %d // %s()\n", result, __FUNCTION__); return result; } YR_API int yr_process_close_iterator(YR_MEMORY_BLOCK_ITERATOR* iterator) { YR_DEBUG_FPRINTF(2, stderr, "- %s() {}\n", __FUNCTION__); YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; if (context != NULL) { _yr_process_detach(context); if (context->buffer != NULL) yr_free((void*) context->buffer); yr_free(context->proc_info); yr_free(context); iterator->context = NULL; } return ERROR_SUCCESS; } yara-4.5.3/libyara/proc/000077500000000000000000000000001501365277300150565ustar00rootroot00000000000000yara-4.5.3/libyara/proc/freebsd.c000066400000000000000000000122401501365277300166330ustar00rootroot00000000000000/* Copyright (c) 2017. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if defined(USE_FREEBSD_PROC) #include #include #include #include #include #include #include #include #include #include #include typedef struct _YR_PROC_INFO { int pid; struct ptrace_vm_entry vm_entry; } YR_PROC_INFO; int _yr_process_attach(int pid, YR_PROC_ITERATOR_CTX* context) { int status; YR_PROC_INFO* proc_info = (YR_PROC_INFO*) yr_malloc(sizeof(YR_PROC_INFO)); if (proc_info == NULL) return ERROR_INSUFFICIENT_MEMORY; memset(proc_info, 0, sizeof(YR_PROC_INFO)); proc_info->pid = pid; if (ptrace(PT_ATTACH, pid, NULL, 0) == -1) { yr_free(proc_info); return ERROR_COULD_NOT_ATTACH_TO_PROCESS; } status = 0; if (waitpid(pid, &status, 0) == -1) { ptrace(PT_DETACH, proc_info->pid, NULL, 0); yr_free(proc_info); return ERROR_COULD_NOT_ATTACH_TO_PROCESS; } context->proc_info = proc_info; return ERROR_SUCCESS; } int _yr_process_detach(YR_PROC_ITERATOR_CTX* context) { YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; ptrace(PT_DETACH, proc_info->pid, NULL, 0); proc_info->vm_entry.pve_path = NULL; return ERROR_SUCCESS; } YR_API const uint8_t* yr_process_fetch_memory_block_data(YR_MEMORY_BLOCK* block) { YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) block->context; YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; struct ptrace_io_desc io_desc; if (context->buffer_size < block->size) { if (context->buffer != NULL) yr_free((void*) context->buffer); context->buffer = (const uint8_t*) yr_malloc(block->size); if (context->buffer != NULL) { context->buffer_size = block->size; } else { context->buffer_size = 0; return NULL; } } io_desc.piod_op = PIOD_READ_D; io_desc.piod_offs = (void*) block->base; io_desc.piod_addr = (void*) context->buffer; io_desc.piod_len = block->size; if (ptrace(PT_IO, proc_info->pid, (char*) &io_desc, 0) == -1) { return NULL; } return context->buffer; } YR_API YR_MEMORY_BLOCK* yr_process_get_next_memory_block( YR_MEMORY_BLOCK_ITERATOR* iterator) { YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; char buf[4096]; proc_info->vm_entry.pve_path = buf; proc_info->vm_entry.pve_pathlen = sizeof(buf); uint64_t current_begin = context->current_block.base + context->current_block.size; uint64_t max_process_memory_chunk; yr_get_configuration_uint64( YR_CONFIG_MAX_PROCESS_MEMORY_CHUNK, &max_process_memory_chunk); iterator->last_error = ERROR_SUCCESS; if (proc_info->vm_entry.pve_end <= current_begin) { if (ptrace( PT_VM_ENTRY, proc_info->pid, (char*) (&proc_info->vm_entry), 0) == -1) { return NULL; } else { current_begin = proc_info->vm_entry.pve_start; } } context->current_block.base = current_begin; context->current_block.size = yr_min( proc_info->vm_entry.pve_end - current_begin + 1, max_process_memory_chunk); assert(context->current_block.size > 0); return &context->current_block; } YR_API YR_MEMORY_BLOCK* yr_process_get_first_memory_block( YR_MEMORY_BLOCK_ITERATOR* iterator) { YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; proc_info->vm_entry.pve_entry = 0; YR_MEMORY_BLOCK* result = yr_process_get_next_memory_block(iterator); if (result == NULL) iterator->last_error = ERROR_COULD_NOT_READ_PROCESS_MEMORY; return result; } #endif yara-4.5.3/libyara/proc/linux.c000066400000000000000000000272121501365277300163650ustar00rootroot00000000000000/* Copyright (c) 2007-2021. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if defined(USE_LINUX_PROC) #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef struct _YR_PROC_INFO { int pid; int mem_fd; int pagemap_fd; FILE* maps; uint64_t map_offset; uint64_t next_block_end; int page_size; char map_path[YR_MAX_PATH]; uint64_t map_dmaj; uint64_t map_dmin; uint64_t map_ino; } YR_PROC_INFO; static int page_size = -1; int _yr_process_attach(int pid, YR_PROC_ITERATOR_CTX* context) { char buffer[256]; page_size = sysconf(_SC_PAGE_SIZE); if (page_size < 0) page_size = 4096; YR_PROC_INFO* proc_info = (YR_PROC_INFO*) yr_malloc(sizeof(YR_PROC_INFO)); if (proc_info == NULL) return ERROR_INSUFFICIENT_MEMORY; proc_info->pid = pid; proc_info->maps = NULL; proc_info->mem_fd = -1; proc_info->pagemap_fd = -1; proc_info->next_block_end = 0; snprintf(buffer, sizeof(buffer), "/proc/%u/maps", pid); proc_info->maps = fopen(buffer, "r"); if (proc_info->maps == NULL) goto err; snprintf(buffer, sizeof(buffer), "/proc/%u/mem", pid); proc_info->mem_fd = open(buffer, O_RDONLY); if (proc_info->mem_fd == -1) goto err; snprintf(buffer, sizeof(buffer), "/proc/%u/pagemap", pid); proc_info->pagemap_fd = open(buffer, O_RDONLY); if (proc_info->pagemap_fd == -1) goto err; context->proc_info = proc_info; return ERROR_SUCCESS; err: if (proc_info) { if (proc_info->pagemap_fd != -1) close(proc_info->pagemap_fd); if (proc_info->mem_fd != -1) close(proc_info->mem_fd); if (proc_info->maps != NULL) fclose(proc_info->maps); yr_free(proc_info); } return ERROR_COULD_NOT_ATTACH_TO_PROCESS; } int _yr_process_detach(YR_PROC_ITERATOR_CTX* context) { YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; if (proc_info) { fclose(proc_info->maps); close(proc_info->mem_fd); close(proc_info->pagemap_fd); } if (context->buffer != NULL) { munmap((void*) context->buffer, context->buffer_size); context->buffer = NULL; context->buffer_size = 0; } return ERROR_SUCCESS; } YR_API const uint8_t* yr_process_fetch_memory_block_data(YR_MEMORY_BLOCK* block) { const uint8_t* result = NULL; uint64_t* pagemap = NULL; YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) block->context; YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; if (context->buffer != NULL) { munmap((void*) context->buffer, context->buffer_size); context->buffer = NULL; context->buffer_size = 0; } int fd = -2; // Assume mapping not connected with a file. // Only try mapping the file if it has a path and belongs to a device if (strlen(proc_info->map_path) > 0 && !(proc_info->map_dmaj == 0 && proc_info->map_dmin == 0)) { struct stat st; if (stat(proc_info->map_path, &st) < 0) { // Why should stat fail after file open? Treat like missing. fd = -1; } else if ( (major(st.st_dev) != proc_info->map_dmaj) || (minor(st.st_dev) != proc_info->map_dmin) || (st.st_ino != proc_info->map_ino)) { // Wrong file, may have been replaced. Treat like missing. fd = -1; } else if (st.st_size < proc_info->map_offset + block->size) { // Mapping extends past end of file. Treat like missing. fd = -1; } else if ((st.st_mode & S_IFMT) != S_IFREG) { // Correct filesystem object, but not a regular file. Treat like // uninitialized mapping. fd = -2; } else { fd = open(proc_info->map_path, O_RDONLY); // Double-check against race conditions struct stat st2; if (fstat(fd, &st2) < 0) { close(fd); fd = -1; } else if ((st.st_dev != st2.st_dev) || (st.st_ino != st2.st_ino)) { // File has been changed from under us, so ignore. close(fd); fd = -1; } } } if (fd >= 0) { context->buffer = mmap( NULL, block->size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, proc_info->map_offset); close(fd); if (context->buffer == MAP_FAILED) { // Notify the code below that we couldn't read from the file // fallback to pread() from the process fd = -1; } context->buffer_size = block->size; } if (fd < 0) { context->buffer = mmap( NULL, block->size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (context->buffer == MAP_FAILED) { context->buffer = NULL; context->buffer_size = 0; goto _exit; } context->buffer_size = block->size; } // If mapping can't be accessed through the filesystem, read everything from // target process VM. if (fd == -1) { if (pread( proc_info->mem_fd, (void*) context->buffer, block->size, block->base) == -1) { goto _exit; } } else { pagemap = calloc(block->size / page_size, sizeof(uint64_t)); if (pagemap == NULL) { goto _exit; } if (pread( proc_info->pagemap_fd, pagemap, sizeof(uint64_t) * block->size / page_size, sizeof(uint64_t) * block->base / page_size) == -1) { goto _exit; } for (uint64_t i = 0; i < block->size / page_size; i++) { if (pagemap[i] >> 61 == 0) { continue; } // Overwrite our mapping if the page is present, file-backed, or // swap-backed and if it differs from our mapping. uint8_t buffer[page_size]; if (pread( proc_info->mem_fd, buffer, page_size, block->base + i * page_size) == -1) { goto _exit; } if (memcmp( (void*) context->buffer + i * page_size, (void*) buffer, page_size) != 0) { memcpy( (void*) context->buffer + i * page_size, (void*) buffer, page_size); } } } result = context->buffer; _exit:; if (pagemap) { free(pagemap); pagemap = NULL; } YR_DEBUG_FPRINTF(2, stderr, "- %s() {} = %p\n", __FUNCTION__, result); return result; } YR_API YR_MEMORY_BLOCK* yr_process_get_next_memory_block( YR_MEMORY_BLOCK_ITERATOR* iterator) { YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; char buffer[YR_MAX_PATH]; char perm[5]; uint64_t begin, end; uint64_t current_begin = context->current_block.base + context->current_block.size; uint64_t max_process_memory_chunk; yr_get_configuration_uint64( YR_CONFIG_MAX_PROCESS_MEMORY_CHUNK, &max_process_memory_chunk); iterator->last_error = ERROR_SUCCESS; if (proc_info->next_block_end <= current_begin) { int path_start, n = 0; char* p; while (fgets(buffer, sizeof(buffer), proc_info->maps) != NULL) { // locate the '\n' character p = strrchr(buffer, '\n'); // If we haven't read the whole line, skip over the rest. if (p == NULL) { int c; do { c = fgetc(proc_info->maps); } while (c >= 0 && c != '\n'); } // otherwise remove '\n' at the end of the line else { *p = '\0'; } // Each row in /proc/$PID/maps describes a region of contiguous virtual // memory in a process or thread. Each row has the following fields: // // address perms offset dev inode pathname // 08048000-08056000 r-xp 00000000 03:0c 64593 /usr/sbin/gpm // n = sscanf( buffer, "%" SCNx64 "-%" SCNx64 " %4s " "%" SCNx64 " %" SCNx64 ":%" SCNx64 " %" SCNu64 " %n", &begin, &end, perm, &(proc_info->map_offset), &(proc_info->map_dmaj), &(proc_info->map_dmin), &(proc_info->map_ino), &path_start); // If the row was parsed correctly sscan must return 7. if (n == 7) { // skip the memory region that doesn't have read permission. if (perm[0] != 'r') { continue; } // path_start contains the offset within buffer where the path starts, // the path should start with /. if (buffer[path_start] == '/') strncpy( proc_info->map_path, buffer + path_start, sizeof(proc_info->map_path) - 1); else proc_info->map_path[0] = '\0'; break; } } if (n == 7) { current_begin = begin; proc_info->next_block_end = end; } else { YR_DEBUG_FPRINTF(2, stderr, "- %s() = NULL\n", __FUNCTION__); return NULL; } } context->current_block.base = current_begin; context->current_block.size = yr_min( proc_info->next_block_end - current_begin, max_process_memory_chunk); assert(context->current_block.size > 0); YR_DEBUG_FPRINTF( 2, stderr, "- %s() {} = %p // .base=0x%" PRIx64 " .size=%" PRIu64 "\n", __FUNCTION__, context->current_block, context->current_block.base, context->current_block.size); return &context->current_block; } YR_API YR_MEMORY_BLOCK* yr_process_get_first_memory_block( YR_MEMORY_BLOCK_ITERATOR* iterator) { YR_DEBUG_FPRINTF(2, stderr, "+ %s() {\n", __FUNCTION__); YR_MEMORY_BLOCK* result = NULL; YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; if (fseek(proc_info->maps, 0, SEEK_SET) != 0) { result = NULL; goto _exit; } proc_info->next_block_end = 0; result = yr_process_get_next_memory_block(iterator); _exit: if (result == NULL) iterator->last_error = ERROR_COULD_NOT_READ_PROCESS_MEMORY; YR_DEBUG_FPRINTF(2, stderr, "} = %p // %s()\n", result, __FUNCTION__); return result; } #endif yara-4.5.3/libyara/proc/mach.c000066400000000000000000000126301501365277300161340ustar00rootroot00000000000000/* Copyright (c) 2007-2017. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if defined(USE_MACH_PROC) #include #include #include #include #include #include #include #include typedef struct _YR_PROC_INFO { task_t task; } YR_PROC_INFO; int _yr_process_attach(int pid, YR_PROC_ITERATOR_CTX* context) { YR_PROC_INFO* proc_info = (YR_PROC_INFO*) yr_malloc(sizeof(YR_PROC_INFO)); if (proc_info == NULL) return ERROR_INSUFFICIENT_MEMORY; kern_return_t kr = task_for_pid(mach_task_self(), pid, &proc_info->task); if (kr != KERN_SUCCESS) { yr_free(proc_info); return ERROR_COULD_NOT_ATTACH_TO_PROCESS; } context->proc_info = proc_info; return ERROR_SUCCESS; } int _yr_process_detach(YR_PROC_ITERATOR_CTX* context) { YR_PROC_INFO* proc_info = context->proc_info; if (proc_info->task != MACH_PORT_NULL) mach_port_deallocate(mach_task_self(), proc_info->task); return ERROR_SUCCESS; } YR_API const uint8_t* yr_process_fetch_memory_block_data(YR_MEMORY_BLOCK* block) { YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) block->context; YR_PROC_INFO* proc_info = context->proc_info; vm_size_t size = block->size; if (context->buffer_size < block->size) { if (context->buffer != NULL) yr_free((void*) context->buffer); context->buffer = (const uint8_t*) yr_malloc(block->size); if (context->buffer != NULL) { context->buffer_size = block->size; } else { context->buffer_size = 0; return NULL; } } if (vm_read_overwrite( proc_info->task, (vm_address_t) block->base, block->size, (vm_address_t) context->buffer, &size) != KERN_SUCCESS) { return NULL; } return context->buffer; } YR_API YR_MEMORY_BLOCK* yr_process_get_next_memory_block( YR_MEMORY_BLOCK_ITERATOR* iterator) { YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; YR_PROC_INFO* proc_info = context->proc_info; kern_return_t kr; mach_msg_type_number_t info_count; mach_port_t object; vm_region_basic_info_data_64_t info; vm_size_t size = 0; uint64_t current_begin = (vm_address_t) context->current_block.base + context->current_block.size; vm_address_t address = current_begin; uint64_t max_process_memory_chunk; yr_get_configuration_uint64( YR_CONFIG_MAX_PROCESS_MEMORY_CHUNK, &max_process_memory_chunk); iterator->last_error = ERROR_SUCCESS; info_count = VM_REGION_BASIC_INFO_COUNT_64; kr = vm_region_64( proc_info->task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t) &info, &info_count, &object); if (kr == KERN_INVALID_ADDRESS) { // The end of the address space has been reached. return NULL; } if (kr != KERN_SUCCESS) { iterator->last_error = ERROR_COULD_NOT_READ_PROCESS_MEMORY; return NULL; } size_t chunk_size; if (current_begin < address) { // current_begin is outside of any region, and the next region was // returned, so advance to it. current_begin = address; chunk_size = size; } else { // address <= current_begin, compute the size for the current chunk. chunk_size = size - (size_t) (current_begin - address); } if (((uint64_t) chunk_size) > max_process_memory_chunk) { chunk_size = (size_t) max_process_memory_chunk; } context->current_block.base = (size_t) current_begin; context->current_block.size = chunk_size; return &context->current_block; } YR_API YR_MEMORY_BLOCK* yr_process_get_first_memory_block( YR_MEMORY_BLOCK_ITERATOR* iterator) { YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; context->current_block.base = 0; context->current_block.size = 0; YR_MEMORY_BLOCK* result = yr_process_get_next_memory_block(iterator); if (result == NULL) iterator->last_error = ERROR_COULD_NOT_READ_PROCESS_MEMORY; return result; } #endif yara-4.5.3/libyara/proc/none.c000066400000000000000000000041631501365277300161650ustar00rootroot00000000000000/* Copyright (c) 2007-2017. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if defined(USE_NO_PROC) #include #include int _yr_process_attach(int pid, YR_PROC_ITERATOR_CTX* context) { return ERROR_COULD_NOT_ATTACH_TO_PROCESS; } int _yr_process_detach(YR_PROC_ITERATOR_CTX* context) { return ERROR_INVALID_ARGUMENT; } YR_API const uint8_t* yr_process_fetch_memory_block_data(YR_MEMORY_BLOCK* block) { return NULL; } YR_API YR_MEMORY_BLOCK* yr_process_get_next_memory_block( YR_MEMORY_BLOCK_ITERATOR* iterator) { iterator->last_error = ERROR_SUCCESS; return NULL; } YR_API YR_MEMORY_BLOCK* yr_process_get_first_memory_block( YR_MEMORY_BLOCK_ITERATOR* iterator) { return NULL; } #endif yara-4.5.3/libyara/proc/openbsd.c000066400000000000000000000132411501365277300166550ustar00rootroot00000000000000/* Copyright (c) 2017. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if defined(USE_OPENBSD_PROC) // Prevent clang-format from complaining about the include order, // changing the order breaks compilation. // // clang-format off #include #include #include #include #include // clang-format on #include #include #include #include #include typedef struct _YR_PROC_INFO { int pid; uint64_t old_end; struct kinfo_vmentry vm_entry; } YR_PROC_INFO; int _yr_process_attach(int pid, YR_PROC_ITERATOR_CTX* context) { int status; size_t len = sizeof(struct kinfo_vmentry); int mib[] = {CTL_KERN, KERN_PROC_VMMAP, pid}; YR_PROC_INFO* proc_info = (YR_PROC_INFO*) yr_malloc(sizeof(YR_PROC_INFO)); if (proc_info == NULL) return ERROR_INSUFFICIENT_MEMORY; memset(proc_info, 0, sizeof(YR_PROC_INFO)); proc_info->pid = pid; if (ptrace(PT_ATTACH, pid, NULL, 0) == -1) { yr_free(proc_info); return ERROR_COULD_NOT_ATTACH_TO_PROCESS; } status = 0; if (waitpid(pid, &status, 0) == -1) { ptrace(PT_DETACH, proc_info->pid, NULL, 0); yr_free(proc_info); return ERROR_COULD_NOT_ATTACH_TO_PROCESS; } if (sysctl(mib, 3, &proc_info->vm_entry, &len, NULL, 0) < 0) { ptrace(PT_DETACH, proc_info->pid, NULL, 0); yr_free(proc_info); return ERROR_COULD_NOT_ATTACH_TO_PROCESS; } context->proc_info = proc_info; return ERROR_SUCCESS; } int _yr_process_detach(YR_PROC_ITERATOR_CTX* context) { YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; ptrace(PT_DETACH, proc_info->pid, NULL, 0); return ERROR_SUCCESS; } YR_API const uint8_t* yr_process_fetch_memory_block_data(YR_MEMORY_BLOCK* block) { YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) block->context; YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; struct ptrace_io_desc io_desc; if (context->buffer_size < block->size) { if (context->buffer != NULL) yr_free((void*) context->buffer); context->buffer = (const uint8_t*) yr_malloc(block->size); if (context->buffer != NULL) { context->buffer_size = block->size; } else { context->buffer_size = 0; return NULL; } } io_desc.piod_op = PIOD_READ_D; io_desc.piod_offs = (void*) block->base; io_desc.piod_addr = (void*) context->buffer; io_desc.piod_len = block->size; if (ptrace(PT_IO, proc_info->pid, (char*) &io_desc, 0) == -1) return NULL; return context->buffer; } YR_API YR_MEMORY_BLOCK* yr_process_get_next_memory_block( YR_MEMORY_BLOCK_ITERATOR* iterator) { YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; int mib[] = {CTL_KERN, KERN_PROC_VMMAP, proc_info->pid}; size_t len = sizeof(struct kinfo_vmentry); uint64_t current_begin = context->current_block.base + context->current_block.size; uint64_t max_process_memory_chunk; yr_get_configuration_uint64( YR_CONFIG_MAX_PROCESS_MEMORY_CHUNK, &max_process_memory_chunk); iterator->last_error = ERROR_SUCCESS; if (proc_info->old_end <= current_begin) { if (sysctl(mib, 3, &proc_info->vm_entry, &len, NULL, 0) < 0) return NULL; // no more blocks if (proc_info->old_end == proc_info->vm_entry.kve_end) return NULL; current_begin = proc_info->vm_entry.kve_start; proc_info->old_end = proc_info->vm_entry.kve_end; proc_info->vm_entry.kve_start = proc_info->vm_entry.kve_start + 1; } context->current_block.base = current_begin; context->current_block.size = yr_min( proc_info->old_end - current_begin, max_process_memory_chunk); assert(context->current_block.size > 0); return &context->current_block; } YR_API YR_MEMORY_BLOCK* yr_process_get_first_memory_block( YR_MEMORY_BLOCK_ITERATOR* iterator) { YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; proc_info->vm_entry.kve_start = 0; YR_MEMORY_BLOCK* result = yr_process_get_next_memory_block(iterator); if (result == NULL) iterator->last_error = ERROR_COULD_NOT_READ_PROCESS_MEMORY; return result; } #endif yara-4.5.3/libyara/proc/windows.c000066400000000000000000000133031501365277300167140ustar00rootroot00000000000000/* Copyright (c) 2007-2017. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #if defined(USE_WINDOWS_PROC) #include #include #include #include #include #include typedef struct _YR_PROC_INFO { HANDLE hProcess; SYSTEM_INFO si; } YR_PROC_INFO; int _yr_process_attach(int pid, YR_PROC_ITERATOR_CTX* context) { TOKEN_PRIVILEGES tokenPriv; LUID luidDebug; HANDLE hToken = NULL; YR_PROC_INFO* proc_info = (YR_PROC_INFO*) yr_malloc(sizeof(YR_PROC_INFO)); if (proc_info == NULL) return ERROR_INSUFFICIENT_MEMORY; if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken) && LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidDebug)) { tokenPriv.PrivilegeCount = 1; tokenPriv.Privileges[0].Luid = luidDebug; tokenPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges( hToken, FALSE, &tokenPriv, sizeof(tokenPriv), NULL, NULL); } if (hToken != NULL) CloseHandle(hToken); proc_info->hProcess = OpenProcess( PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, pid); if (proc_info->hProcess == NULL) { yr_free(proc_info); return ERROR_COULD_NOT_ATTACH_TO_PROCESS; } GetSystemInfo(&proc_info->si); context->proc_info = proc_info; return ERROR_SUCCESS; } int _yr_process_detach(YR_PROC_ITERATOR_CTX* context) { YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; CloseHandle(proc_info->hProcess); return ERROR_SUCCESS; } YR_API const uint8_t* yr_process_fetch_memory_block_data(YR_MEMORY_BLOCK* block) { SIZE_T read; YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) block->context; YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; if (context->buffer_size < block->size) { if (context->buffer != NULL) yr_free((void*) context->buffer); context->buffer = (const uint8_t*) yr_malloc(block->size); if (context->buffer != NULL) { context->buffer_size = block->size; } else { context->buffer_size = 0; return NULL; } } if (ReadProcessMemory( proc_info->hProcess, (LPCVOID) block->base, (LPVOID) context->buffer, (SIZE_T) block->size, &read) == FALSE) { return NULL; } return context->buffer; } YR_API YR_MEMORY_BLOCK* yr_process_get_next_memory_block( YR_MEMORY_BLOCK_ITERATOR* iterator) { YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; MEMORY_BASIC_INFORMATION mbi; void* address = (void*) (context->current_block.base + context->current_block.size); uint64_t max_process_memory_chunk; yr_get_configuration_uint64( YR_CONFIG_MAX_PROCESS_MEMORY_CHUNK, &max_process_memory_chunk); iterator->last_error = ERROR_SUCCESS; while (address < proc_info->si.lpMaximumApplicationAddress && VirtualQueryEx(proc_info->hProcess, address, &mbi, sizeof(mbi)) != 0) { // mbi.RegionSize can overflow address while scanning a 64-bit process // with a 32-bit YARA. if ((uint8_t*) address + mbi.RegionSize <= (uint8_t*) address) break; if (mbi.State == MEM_COMMIT && ((mbi.Protect & PAGE_NOACCESS) == 0)) { size_t chuck_size = mbi.RegionSize - (size_t) (((uint8_t*) address) - ((uint8_t*) mbi.BaseAddress)); if (((uint64_t) chuck_size) > max_process_memory_chunk) { chuck_size = (size_t) max_process_memory_chunk; } context->current_block.base = (size_t) address; context->current_block.size = chuck_size; return &context->current_block; } address = (uint8_t*) mbi.BaseAddress + mbi.RegionSize; } return NULL; } YR_API YR_MEMORY_BLOCK* yr_process_get_first_memory_block( YR_MEMORY_BLOCK_ITERATOR* iterator) { YR_PROC_ITERATOR_CTX* context = (YR_PROC_ITERATOR_CTX*) iterator->context; YR_PROC_INFO* proc_info = (YR_PROC_INFO*) context->proc_info; context->current_block.size = 0; context->current_block.base = (size_t) proc_info->si.lpMinimumApplicationAddress; YR_MEMORY_BLOCK* result = yr_process_get_next_memory_block(iterator); if (result == NULL) iterator->last_error = ERROR_COULD_NOT_READ_PROCESS_MEMORY; return result; } #endif yara-4.5.3/libyara/re.c000066400000000000000000002143701501365277300146740ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* This module implements a regular expressions engine based on Thompson's algorithm as described by Russ Cox in http://swtch.com/~rsc/regexp/regexp2.html. What the article names a "thread" has been named a "fiber" in this code, in order to avoid confusion with operating system threads. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define EMIT_BACKWARDS 0x01 #define EMIT_DONT_SET_FORWARDS_CODE 0x02 #define EMIT_DONT_SET_BACKWARDS_CODE 0x04 #ifndef INT16_MAX #define INT16_MAX (32767) #endif typedef uint8_t RE_SPLIT_ID_TYPE; // RE_REPEAT_ARGS and RE_REPEAT_ANY_ARGS are structures that are embedded in // the regexp's instruction stream. As such, they are not always aligned to // 8-byte boundaries, so they need to be "packed" structures in order to prevent // issues due to unaligned memory accesses. #pragma pack(push) #pragma pack(1) typedef struct _RE_REPEAT_ARGS { uint16_t min; uint16_t max; int32_t offset; } RE_REPEAT_ARGS; typedef struct _RE_REPEAT_ANY_ARGS { uint16_t min; uint16_t max; } RE_REPEAT_ANY_ARGS; #pragma pack(pop) typedef struct _RE_EMIT_CONTEXT { YR_ARENA* arena; RE_SPLIT_ID_TYPE next_split_id; } RE_EMIT_CONTEXT; #define CHAR_IN_CLASS(cls, chr) ((cls)[(chr) / 8] & 1 << ((chr) % 8)) static bool _yr_re_is_char_in_class( RE_CLASS* re_class, uint8_t chr, int case_insensitive) { int result = CHAR_IN_CLASS(re_class->bitmap, chr); if (case_insensitive) result |= CHAR_IN_CLASS(re_class->bitmap, yr_altercase[chr]); if (re_class->negated) result = !result; return result; } static bool _yr_re_is_word_char(const uint8_t* input, uint8_t character_size) { int result = ((yr_isalnum(input) || (*input) == '_')); if (character_size == 2) result = result && (*(input + 1) == 0); return result; } RE_NODE* yr_re_node_create(int type) { RE_NODE* result = (RE_NODE*) yr_malloc(sizeof(RE_NODE)); if (result != NULL) { result->type = type; result->children_head = NULL; result->children_tail = NULL; result->prev_sibling = NULL; result->next_sibling = NULL; result->greedy = true; result->forward_code_ref = YR_ARENA_NULL_REF; result->backward_code_ref = YR_ARENA_NULL_REF; } return result; } void yr_re_node_destroy(RE_NODE* node) { RE_NODE* child = node->children_head; RE_NODE* next_child; while (child != NULL) { next_child = child->next_sibling; yr_re_node_destroy(child); child = next_child; } if (node->type == RE_NODE_CLASS) yr_free(node->re_class); yr_free(node); } //////////////////////////////////////////////////////////////////////////////// // Appends a node to the end of the children list. // void yr_re_node_append_child(RE_NODE* node, RE_NODE* child) { if (node->children_head == NULL) node->children_head = child; if (node->children_tail != NULL) node->children_tail->next_sibling = child; child->prev_sibling = node->children_tail; node->children_tail = child; } //////////////////////////////////////////////////////////////////////////////// // Appends a node to the beginning of the children list. // void yr_re_node_prepend_child(RE_NODE* node, RE_NODE* child) { child->next_sibling = node->children_head; if (node->children_head != NULL) node->children_head->prev_sibling = child; node->children_head = child; if (node->children_tail == NULL) node->children_tail = child; } int yr_re_ast_create(RE_AST** re_ast) { *re_ast = (RE_AST*) yr_malloc(sizeof(RE_AST)); if (*re_ast == NULL) return ERROR_INSUFFICIENT_MEMORY; (*re_ast)->flags = 0; (*re_ast)->root_node = NULL; return ERROR_SUCCESS; } void yr_re_ast_destroy(RE_AST* re_ast) { if (re_ast->root_node != NULL) yr_re_node_destroy(re_ast->root_node); yr_free(re_ast); } //////////////////////////////////////////////////////////////////////////////// // Parses a regexp but don't emit its code. A further call to // yr_re_ast_emit_code is required to get the code. // int yr_re_parse( const char* re_string, RE_AST** re_ast, RE_ERROR* error, int flags) { return yr_parse_re_string(re_string, re_ast, error, flags); } //////////////////////////////////////////////////////////////////////////////// // Parses a hex string but don't emit its code. A further call to // yr_re_ast_emit_code is required to get the code. // int yr_re_parse_hex(const char* hex_string, RE_AST** re_ast, RE_ERROR* error) { return yr_parse_hex_string(hex_string, re_ast, error); } //////////////////////////////////////////////////////////////////////////////// // Parses the regexp and emit its code to the provided to the // YR_RE_CODE_SECTION in the specified arena. // int yr_re_compile( const char* re_string, int flags, int parser_flags, YR_ARENA* arena, YR_ARENA_REF* ref, RE_ERROR* error) { RE_AST* re_ast; RE _re; int result; result = yr_re_parse(re_string, &re_ast, error, parser_flags); if (result != ERROR_UNKNOWN_ESCAPE_SEQUENCE) FAIL_ON_ERROR(result); _re.flags = flags; FAIL_ON_ERROR_WITH_CLEANUP( yr_arena_write_data(arena, YR_RE_CODE_SECTION, &_re, sizeof(_re), ref), yr_re_ast_destroy(re_ast)); FAIL_ON_ERROR_WITH_CLEANUP( yr_re_ast_emit_code(re_ast, arena, false), yr_re_ast_destroy(re_ast)); yr_re_ast_destroy(re_ast); return result; } //////////////////////////////////////////////////////////////////////////////// // Verifies if the target string matches the pattern // // Args: // context: Scan context // re: A pointer to a compiled regexp // target: Target string // // Returns: // See return codes for yr_re_exec // int yr_re_match(YR_SCAN_CONTEXT* context, RE* re, const char* target) { int result; yr_re_exec( context, re->code, (uint8_t*) target, strlen(target), 0, re->flags | RE_FLAGS_SCAN, NULL, NULL, &result); return result; } //////////////////////////////////////////////////////////////////////////////// // Verifies if the provided regular expression is just a literal string // like "abc", "12345", without any wildcard, operator, etc. In that case // returns the string as a SIZED_STRING, or returns NULL if otherwise. // // The caller is responsible for deallocating the returned SIZED_STRING by // calling yr_free. // SIZED_STRING* yr_re_ast_extract_literal(RE_AST* re_ast) { SIZED_STRING* string; RE_NODE* child; int length = 0; if (re_ast->root_node->type == RE_NODE_LITERAL) { length = 1; } else if (re_ast->root_node->type == RE_NODE_CONCAT) { child = re_ast->root_node->children_tail; while (child != NULL && child->type == RE_NODE_LITERAL) { length++; child = child->prev_sibling; } if (child != NULL) return NULL; } else { return NULL; } string = (SIZED_STRING*) yr_malloc(sizeof(SIZED_STRING) + length); if (string == NULL) return NULL; string->length = length; string->flags = 0; if (re_ast->root_node->type == RE_NODE_LITERAL) { string->c_string[0] = re_ast->root_node->value; } else { child = re_ast->root_node->children_tail; while (child != NULL) { string->c_string[--length] = child->value; child = child->prev_sibling; } } string->c_string[string->length] = '\0'; return string; } int _yr_re_node_has_unbounded_quantifier_for_dot(RE_NODE* re_node) { RE_NODE* child; if ((re_node->type == RE_NODE_STAR || re_node->type == RE_NODE_PLUS) && re_node->children_head->type == RE_NODE_ANY) return true; if (re_node->type == RE_NODE_RANGE_ANY && re_node->end == RE_MAX_RANGE) return true; if (re_node->type == RE_NODE_CONCAT) { child = re_node->children_tail; while (child != NULL) { if (_yr_re_node_has_unbounded_quantifier_for_dot(child)) return true; child = child->prev_sibling; } } return false; } //////////////////////////////////////////////////////////////////////////////// // Detects the use of .*, .+ or .{x,} in a regexp. The use of wildcards with // quantifiers that don't have a reasonably small upper bound causes a // performance penalty. This function detects such cases in order to warn the // user about this. // int yr_re_ast_has_unbounded_quantifier_for_dot(RE_AST* re_ast) { return _yr_re_node_has_unbounded_quantifier_for_dot(re_ast->root_node); } //////////////////////////////////////////////////////////////////////////////// // In some cases splitting a regular expression (or hex string) in two parts is // convenient for increasing performance. This happens when the pattern contains // a large gap (a.k.a jump), for example: { 01 02 03 [0-999] 04 05 06 } // In this case the string is splitted in { 01 02 03 } and { 04 05 06 } where // the latter is chained to the former. This means that { 01 02 03 } and // { 04 05 06 } are handled as individual strings, and when both of them are // found, YARA verifies if the distance between the matches complies with the // [0-999] restriction. // // This function traverses a regexp's AST looking for nodes where it should be // splitted. It must be noticed that this only applies to two-level ASTs (i.e. // an AST consisting in a RE_NODE_CONCAT at the root where all the children are // leaves). // // For example, { 01 02 03 [0-1000] 04 05 06 [500-2000] 07 08 09 } has the // following AST: // // RE_NODE_CONCAT // | // |- RE_NODE_LITERAL (01) // |- RE_NODE_LITERAL (02) // |- RE_NODE_LITERAL (03) // |- RE_NODE_RANGE_ANY (start=0, end=1000) // |- RE_NODE_LITERAL (04) // |- RE_NODE_LITERAL (05) // |- RE_NODE_LITERAL (06) // |- RE_NODE_RANGE_ANY (start=500, end=2000) // |- RE_NODE_LITERAL (07) // |- RE_NODE_LITERAL (08) // |- RE_NODE_LITERAL (09) // // If the AST above is passed in the re_ast argument, it will be trimmed to: // // RE_NODE_CONCAT // | // |- RE_NODE_LITERAL (01) // |- RE_NODE_LITERAL (02) // |- RE_NODE_LITERAL (03) // // While remainder_re_ast will be: // // RE_NODE_CONCAT // | // |- RE_NODE_LITERAL (04) // |- RE_NODE_LITERAL (05) // |- RE_NODE_LITERAL (06) // |- RE_NODE_RANGE_ANY (start=500, end=2000) // |- RE_NODE_LITERAL (07) // |- RE_NODE_LITERAL (08) // |- RE_NODE_LITERAL (09) // // The caller is responsible for freeing the new AST in remainder_re_ast by // calling yr_re_ast_destroy. // // The integers pointed to by min_gap and max_gap will be filled with the // minimum and maximum gap size between the sub-strings represented by the // two ASTs. // int yr_re_ast_split_at_chaining_point( RE_AST* re_ast, RE_AST** remainder_re_ast, int32_t* min_gap, int32_t* max_gap) { RE_NODE* child; RE_NODE* concat; int result; *remainder_re_ast = NULL; *min_gap = 0; *max_gap = 0; if (re_ast->root_node->type != RE_NODE_CONCAT) return ERROR_SUCCESS; child = re_ast->root_node->children_head; while (child != NULL) { if (!child->greedy && child->type == RE_NODE_RANGE_ANY && child->prev_sibling != NULL && child->next_sibling != NULL && (child->start > YR_STRING_CHAINING_THRESHOLD || child->end > YR_STRING_CHAINING_THRESHOLD)) { result = yr_re_ast_create(remainder_re_ast); if (result != ERROR_SUCCESS) return result; concat = yr_re_node_create(RE_NODE_CONCAT); if (concat == NULL) return ERROR_INSUFFICIENT_MEMORY; concat->children_head = child->next_sibling; concat->children_tail = re_ast->root_node->children_tail; re_ast->root_node->children_tail = child->prev_sibling; child->prev_sibling->next_sibling = NULL; child->next_sibling->prev_sibling = NULL; *min_gap = child->start; *max_gap = child->end; (*remainder_re_ast)->root_node = concat; (*remainder_re_ast)->flags = re_ast->flags; yr_re_node_destroy(child); return ERROR_SUCCESS; } child = child->next_sibling; } return ERROR_SUCCESS; } int _yr_emit_inst( RE_EMIT_CONTEXT* emit_context, uint8_t opcode, YR_ARENA_REF* instruction_ref) { FAIL_ON_ERROR(yr_arena_write_data( emit_context->arena, YR_RE_CODE_SECTION, &opcode, sizeof(uint8_t), instruction_ref)); return ERROR_SUCCESS; } int _yr_emit_inst_arg_uint8( RE_EMIT_CONTEXT* emit_context, uint8_t opcode, uint8_t argument, YR_ARENA_REF* instruction_ref, YR_ARENA_REF* argument_ref) { FAIL_ON_ERROR(yr_arena_write_data( emit_context->arena, YR_RE_CODE_SECTION, &opcode, sizeof(uint8_t), instruction_ref)); FAIL_ON_ERROR(yr_arena_write_data( emit_context->arena, YR_RE_CODE_SECTION, &argument, sizeof(uint8_t), argument_ref)); return ERROR_SUCCESS; } int _yr_emit_inst_arg_uint16( RE_EMIT_CONTEXT* emit_context, uint8_t opcode, uint16_t argument, YR_ARENA_REF* instruction_ref, YR_ARENA_REF* argument_ref) { FAIL_ON_ERROR(yr_arena_write_data( emit_context->arena, YR_RE_CODE_SECTION, &opcode, sizeof(uint8_t), instruction_ref)); FAIL_ON_ERROR(yr_arena_write_data( emit_context->arena, YR_RE_CODE_SECTION, &argument, sizeof(uint16_t), argument_ref)); return ERROR_SUCCESS; } int _yr_emit_inst_arg_uint32( RE_EMIT_CONTEXT* emit_context, uint8_t opcode, uint32_t argument, YR_ARENA_REF* instruction_ref, YR_ARENA_REF* argument_ref) { FAIL_ON_ERROR(yr_arena_write_data( emit_context->arena, YR_RE_CODE_SECTION, &opcode, sizeof(uint8_t), instruction_ref)); FAIL_ON_ERROR(yr_arena_write_data( emit_context->arena, YR_RE_CODE_SECTION, &argument, sizeof(uint32_t), argument_ref)); return ERROR_SUCCESS; } int _yr_emit_inst_arg_int16( RE_EMIT_CONTEXT* emit_context, uint8_t opcode, int16_t argument, YR_ARENA_REF* instruction_ref, YR_ARENA_REF* argument_ref) { FAIL_ON_ERROR(yr_arena_write_data( emit_context->arena, YR_RE_CODE_SECTION, &opcode, sizeof(uint8_t), instruction_ref)); FAIL_ON_ERROR(yr_arena_write_data( emit_context->arena, YR_RE_CODE_SECTION, &argument, sizeof(int16_t), argument_ref)); return ERROR_SUCCESS; } int _yr_emit_inst_arg_struct( RE_EMIT_CONTEXT* emit_context, uint8_t opcode, void* structure, size_t structure_size, YR_ARENA_REF* instruction_ref, YR_ARENA_REF* argument_ref) { FAIL_ON_ERROR(yr_arena_write_data( emit_context->arena, YR_RE_CODE_SECTION, &opcode, sizeof(uint8_t), instruction_ref)); FAIL_ON_ERROR(yr_arena_write_data( emit_context->arena, YR_RE_CODE_SECTION, structure, structure_size, argument_ref)); return ERROR_SUCCESS; } int _yr_emit_split( RE_EMIT_CONTEXT* emit_context, uint8_t opcode, int16_t argument, YR_ARENA_REF* instruction_ref, YR_ARENA_REF* argument_ref) { assert(opcode == RE_OPCODE_SPLIT_A || opcode == RE_OPCODE_SPLIT_B); if (emit_context->next_split_id == RE_MAX_SPLIT_ID) return ERROR_REGULAR_EXPRESSION_TOO_COMPLEX; FAIL_ON_ERROR(yr_arena_write_data( emit_context->arena, YR_RE_CODE_SECTION, &opcode, sizeof(uint8_t), instruction_ref)); FAIL_ON_ERROR(yr_arena_write_data( emit_context->arena, YR_RE_CODE_SECTION, &emit_context->next_split_id, sizeof(RE_SPLIT_ID_TYPE), NULL)); emit_context->next_split_id++; FAIL_ON_ERROR(yr_arena_write_data( emit_context->arena, YR_RE_CODE_SECTION, &argument, sizeof(int16_t), argument_ref)); return ERROR_SUCCESS; } static int _yr_re_emit( RE_EMIT_CONTEXT* emit_context, RE_NODE* re_node, int flags, YR_ARENA_REF* code_ref) { int16_t jmp_offset; yr_arena_off_t bookmark_1 = 0; yr_arena_off_t bookmark_2 = 0; yr_arena_off_t bookmark_3 = 0; yr_arena_off_t bookmark_4 = 0; bool emit_split; bool emit_repeat; bool emit_prolog; bool emit_epilog; RE_REPEAT_ARGS repeat_args; RE_REPEAT_ARGS* repeat_start_args_addr; RE_REPEAT_ANY_ARGS repeat_any_args; RE_NODE* child; int16_t* split_offset_addr = NULL; int16_t* jmp_offset_addr = NULL; YR_ARENA_REF instruction_ref = YR_ARENA_NULL_REF; YR_ARENA_REF split_offset_ref; YR_ARENA_REF jmp_instruction_ref; YR_ARENA_REF jmp_offset_ref; YR_ARENA_REF repeat_start_args_ref; switch (re_node->type) { case RE_NODE_LITERAL: FAIL_ON_ERROR(_yr_emit_inst_arg_uint8( emit_context, RE_OPCODE_LITERAL, re_node->value, &instruction_ref, NULL)); break; case RE_NODE_NOT_LITERAL: FAIL_ON_ERROR(_yr_emit_inst_arg_uint8( emit_context, RE_OPCODE_NOT_LITERAL, re_node->value, &instruction_ref, NULL)); break; case RE_NODE_MASKED_LITERAL: FAIL_ON_ERROR(_yr_emit_inst_arg_uint16( emit_context, RE_OPCODE_MASKED_LITERAL, re_node->mask << 8 | re_node->value, &instruction_ref, NULL)); break; case RE_NODE_MASKED_NOT_LITERAL: FAIL_ON_ERROR(_yr_emit_inst_arg_uint16( emit_context, RE_OPCODE_MASKED_NOT_LITERAL, re_node->mask << 8 | re_node->value, &instruction_ref, NULL)); break; case RE_NODE_WORD_CHAR: FAIL_ON_ERROR( _yr_emit_inst(emit_context, RE_OPCODE_WORD_CHAR, &instruction_ref)); break; case RE_NODE_NON_WORD_CHAR: FAIL_ON_ERROR( _yr_emit_inst(emit_context, RE_OPCODE_NON_WORD_CHAR, &instruction_ref)); break; case RE_NODE_WORD_BOUNDARY: FAIL_ON_ERROR( _yr_emit_inst(emit_context, RE_OPCODE_WORD_BOUNDARY, &instruction_ref)); break; case RE_NODE_NON_WORD_BOUNDARY: FAIL_ON_ERROR(_yr_emit_inst( emit_context, RE_OPCODE_NON_WORD_BOUNDARY, &instruction_ref)); break; case RE_NODE_SPACE: FAIL_ON_ERROR( _yr_emit_inst(emit_context, RE_OPCODE_SPACE, &instruction_ref)); break; case RE_NODE_NON_SPACE: FAIL_ON_ERROR( _yr_emit_inst(emit_context, RE_OPCODE_NON_SPACE, &instruction_ref)); break; case RE_NODE_DIGIT: FAIL_ON_ERROR( _yr_emit_inst(emit_context, RE_OPCODE_DIGIT, &instruction_ref)); break; case RE_NODE_NON_DIGIT: FAIL_ON_ERROR( _yr_emit_inst(emit_context, RE_OPCODE_NON_DIGIT, &instruction_ref)); break; case RE_NODE_ANY: FAIL_ON_ERROR(_yr_emit_inst(emit_context, RE_OPCODE_ANY, &instruction_ref)); break; case RE_NODE_CLASS: FAIL_ON_ERROR( _yr_emit_inst(emit_context, RE_OPCODE_CLASS, &instruction_ref)); FAIL_ON_ERROR(yr_arena_write_data( emit_context->arena, YR_RE_CODE_SECTION, re_node->re_class, sizeof(*re_node->re_class), NULL)); break; case RE_NODE_ANCHOR_START: FAIL_ON_ERROR(_yr_emit_inst( emit_context, RE_OPCODE_MATCH_AT_START, &instruction_ref)); break; case RE_NODE_ANCHOR_END: FAIL_ON_ERROR( _yr_emit_inst(emit_context, RE_OPCODE_MATCH_AT_END, &instruction_ref)); break; case RE_NODE_CONCAT: FAIL_ON_ERROR(_yr_re_emit( emit_context, (flags & EMIT_BACKWARDS) ? re_node->children_tail : re_node->children_head, flags, &instruction_ref)); if (flags & EMIT_BACKWARDS) child = re_node->children_tail->prev_sibling; else child = re_node->children_head->next_sibling; while (child != NULL) { FAIL_ON_ERROR(_yr_re_emit(emit_context, child, flags, NULL)); child = (flags & EMIT_BACKWARDS) ? child->prev_sibling : child->next_sibling; } break; case RE_NODE_PLUS: // Code for e+ looks like: // // L1: code for e // split L1, L2 // L2: // FAIL_ON_ERROR(_yr_re_emit( emit_context, re_node->children_head, flags, &instruction_ref)); bookmark_1 = yr_arena_get_current_offset( emit_context->arena, YR_RE_CODE_SECTION); if (instruction_ref.offset - bookmark_1 < INT16_MIN) return ERROR_REGULAR_EXPRESSION_TOO_LARGE; jmp_offset = (int16_t) (instruction_ref.offset - bookmark_1); FAIL_ON_ERROR(_yr_emit_split( emit_context, re_node->greedy ? RE_OPCODE_SPLIT_B : RE_OPCODE_SPLIT_A, jmp_offset, NULL, NULL)); break; case RE_NODE_STAR: // Code for e* looks like: // // L1: split L1, L2 // code for e // jmp L1 // L2: FAIL_ON_ERROR(_yr_emit_split( emit_context, re_node->greedy ? RE_OPCODE_SPLIT_A : RE_OPCODE_SPLIT_B, 0, &instruction_ref, &split_offset_ref)); FAIL_ON_ERROR( _yr_re_emit(emit_context, re_node->children_head, flags, NULL)); bookmark_1 = yr_arena_get_current_offset( emit_context->arena, YR_RE_CODE_SECTION); if (instruction_ref.offset - bookmark_1 < INT16_MIN) return ERROR_REGULAR_EXPRESSION_TOO_LARGE; jmp_offset = (int16_t) (instruction_ref.offset - bookmark_1); // Emit jump with offset set to 0. FAIL_ON_ERROR(_yr_emit_inst_arg_int16( emit_context, RE_OPCODE_JUMP, jmp_offset, NULL, NULL)); bookmark_1 = yr_arena_get_current_offset( emit_context->arena, YR_RE_CODE_SECTION); if (bookmark_1 - instruction_ref.offset > INT16_MAX) return ERROR_REGULAR_EXPRESSION_TOO_LARGE; jmp_offset = (int16_t) (bookmark_1 - instruction_ref.offset); // Update split offset. split_offset_addr = (int16_t*) yr_arena_ref_to_ptr( emit_context->arena, &split_offset_ref); memcpy(split_offset_addr, &jmp_offset, sizeof(jmp_offset)); break; case RE_NODE_ALT: // Code for e1|e2 looks like: // // split L1, L2 // L1: code for e1 // jmp L3 // L2: code for e2 // L3: // Emit a split instruction with offset set to 0 temporarily. Offset // will be updated after we know the size of the code generated for // the left node (e1). FAIL_ON_ERROR(_yr_emit_split( emit_context, RE_OPCODE_SPLIT_A, 0, &instruction_ref, &split_offset_ref)); FAIL_ON_ERROR( _yr_re_emit(emit_context, re_node->children_head, flags, NULL)); // Emit jump with offset set to 0. FAIL_ON_ERROR(_yr_emit_inst_arg_int16( emit_context, RE_OPCODE_JUMP, 0, &jmp_instruction_ref, &jmp_offset_ref)); bookmark_1 = yr_arena_get_current_offset( emit_context->arena, YR_RE_CODE_SECTION); if (bookmark_1 - instruction_ref.offset > INT16_MAX) return ERROR_REGULAR_EXPRESSION_TOO_LARGE; jmp_offset = (int16_t) (bookmark_1 - instruction_ref.offset); // Update split offset. split_offset_addr = (int16_t*) yr_arena_ref_to_ptr( emit_context->arena, &split_offset_ref); memcpy(split_offset_addr, &jmp_offset, sizeof(jmp_offset)); FAIL_ON_ERROR( _yr_re_emit(emit_context, re_node->children_tail, flags, NULL)); bookmark_1 = yr_arena_get_current_offset( emit_context->arena, YR_RE_CODE_SECTION); if (bookmark_1 - jmp_instruction_ref.offset > INT16_MAX) return ERROR_REGULAR_EXPRESSION_TOO_LARGE; jmp_offset = (int16_t) (bookmark_1 - jmp_instruction_ref.offset); // Update offset for jmp instruction. jmp_offset_addr = (int16_t*) yr_arena_ref_to_ptr( emit_context->arena, &jmp_offset_ref); memcpy(jmp_offset_addr, &jmp_offset, sizeof(jmp_offset)); break; case RE_NODE_RANGE_ANY: repeat_any_args.min = re_node->start; repeat_any_args.max = re_node->end; FAIL_ON_ERROR(_yr_emit_inst_arg_struct( emit_context, re_node->greedy ? RE_OPCODE_REPEAT_ANY_GREEDY : RE_OPCODE_REPEAT_ANY_UNGREEDY, &repeat_any_args, sizeof(repeat_any_args), &instruction_ref, NULL)); break; case RE_NODE_RANGE: // Code for e{n,m} looks like: // // code for e --- prolog // repeat_start n, m, L1 --+ // L0: code for e | repeat // repeat_end n, m, L0 --+ // L1: split L2, L3 --- split // L2: code for e --- epilog // L3: // // Not all sections (prolog, repeat, split and epilog) are generated in all // cases, it depends on the values of n and m. The following table shows // which sections are generated for the first few values of n and m. // // n,m prolog repeat split epilog // (min,max) // --------------------------------------- // 0,0 - - - - // 0,1 - - X X // 0,2 - 0,1 X X // 0,3 - 0,2 X X // 0,M - 0,M-1 X X // // 1,1 X - - - // 1,2 X - X X // 1,3 X 0,1 X X // 1,4 X 1,2 X X // 1,M X 1,M-2 X X // // 2,2 X - - X // 2,3 X 1,1 X X // 2,4 X 1,2 X X // 2,M X 1,M-2 X X // // 3,3 X 1,1 - X // 3,4 X 2,2 X X // 3,M X 2,M-2 X X // // 4,4 X 2,2 - X // 4,5 X 3,3 X X // 4,M X 3,M-2 X X // // The code can't consists simply in the repeat section, the prolog and // epilog are required because we can't have atoms pointing to code inside // the repeat loop. Atoms' forwards_code will point to code in the prolog // and backwards_code will point to code in the epilog (or in prolog if // epilog wasn't generated, like in n=1,m=1) emit_prolog = re_node->start > 0; emit_repeat = re_node->end > re_node->start + 1 || re_node->end > 2; emit_split = re_node->end > re_node->start; emit_epilog = re_node->end > re_node->start || re_node->end > 1; if (emit_prolog) { FAIL_ON_ERROR(_yr_re_emit( emit_context, re_node->children_head, flags, &instruction_ref)); } if (emit_repeat) { repeat_args.min = re_node->start; repeat_args.max = re_node->end; if (emit_prolog) { repeat_args.max--; repeat_args.min--; } if (emit_split) { repeat_args.max--; } else { repeat_args.min--; repeat_args.max--; } repeat_args.offset = 0; bookmark_1 = yr_arena_get_current_offset( emit_context->arena, YR_RE_CODE_SECTION); FAIL_ON_ERROR(_yr_emit_inst_arg_struct( emit_context, re_node->greedy ? RE_OPCODE_REPEAT_START_GREEDY : RE_OPCODE_REPEAT_START_UNGREEDY, &repeat_args, sizeof(repeat_args), emit_prolog ? NULL : &instruction_ref, &repeat_start_args_ref)); bookmark_2 = yr_arena_get_current_offset( emit_context->arena, YR_RE_CODE_SECTION); FAIL_ON_ERROR(_yr_re_emit( emit_context, re_node->children_head, flags | EMIT_DONT_SET_FORWARDS_CODE | EMIT_DONT_SET_BACKWARDS_CODE, NULL)); bookmark_3 = yr_arena_get_current_offset( emit_context->arena, YR_RE_CODE_SECTION); if (bookmark_2 - bookmark_3 < INT32_MIN) return ERROR_REGULAR_EXPRESSION_TOO_LARGE; repeat_args.offset = (int32_t) (bookmark_2 - bookmark_3); FAIL_ON_ERROR(_yr_emit_inst_arg_struct( emit_context, re_node->greedy ? RE_OPCODE_REPEAT_END_GREEDY : RE_OPCODE_REPEAT_END_UNGREEDY, &repeat_args, sizeof(repeat_args), NULL, NULL)); bookmark_4 = yr_arena_get_current_offset( emit_context->arena, YR_RE_CODE_SECTION); repeat_start_args_addr = (RE_REPEAT_ARGS*) yr_arena_ref_to_ptr( emit_context->arena, &repeat_start_args_ref); if (bookmark_4 - bookmark_1 > INT32_MAX) return ERROR_REGULAR_EXPRESSION_TOO_LARGE; repeat_start_args_addr->offset = (int32_t) (bookmark_4 - bookmark_1); } if (emit_split) { bookmark_1 = yr_arena_get_current_offset( emit_context->arena, YR_RE_CODE_SECTION); FAIL_ON_ERROR(_yr_emit_split( emit_context, re_node->greedy ? RE_OPCODE_SPLIT_A : RE_OPCODE_SPLIT_B, 0, NULL, &split_offset_ref)); } if (emit_epilog) { FAIL_ON_ERROR(_yr_re_emit( emit_context, re_node->children_head, emit_prolog ? flags | EMIT_DONT_SET_FORWARDS_CODE : flags, emit_prolog || emit_repeat ? NULL : &instruction_ref)); } if (emit_split) { bookmark_2 = yr_arena_get_current_offset( emit_context->arena, YR_RE_CODE_SECTION); if (bookmark_2 - bookmark_1 > INT16_MAX) return ERROR_REGULAR_EXPRESSION_TOO_LARGE; split_offset_addr = (int16_t*) yr_arena_ref_to_ptr( emit_context->arena, &split_offset_ref); jmp_offset = (int16_t) (bookmark_2 - bookmark_1); memcpy(split_offset_addr, &jmp_offset, sizeof(jmp_offset)); } break; } if (flags & EMIT_BACKWARDS) { if (!(flags & EMIT_DONT_SET_BACKWARDS_CODE)) { re_node->backward_code_ref.buffer_id = YR_RE_CODE_SECTION; re_node->backward_code_ref.offset = yr_arena_get_current_offset( emit_context->arena, YR_RE_CODE_SECTION); } } else { if (!(flags & EMIT_DONT_SET_FORWARDS_CODE)) { re_node->forward_code_ref = instruction_ref; } } if (code_ref != NULL) *code_ref = instruction_ref; return ERROR_SUCCESS; } int yr_re_ast_emit_code(RE_AST* re_ast, YR_ARENA* arena, int backwards_code) { RE_EMIT_CONTEXT emit_context; // Emit code for matching the regular expressions forwards. emit_context.arena = arena; emit_context.next_split_id = 0; FAIL_ON_ERROR(_yr_re_emit( &emit_context, re_ast->root_node, backwards_code ? EMIT_BACKWARDS : 0, NULL)); FAIL_ON_ERROR(_yr_emit_inst(&emit_context, RE_OPCODE_MATCH, NULL)); return ERROR_SUCCESS; } static int _yr_re_fiber_create(RE_FIBER_POOL* fiber_pool, RE_FIBER** new_fiber) { RE_FIBER* fiber; if (fiber_pool->fibers.head != NULL) { fiber = fiber_pool->fibers.head; fiber_pool->fibers.head = fiber->next; if (fiber_pool->fibers.tail == fiber) fiber_pool->fibers.tail = NULL; } else { if (fiber_pool->fiber_count == RE_MAX_FIBERS) return ERROR_TOO_MANY_RE_FIBERS; fiber = (RE_FIBER*) yr_malloc(sizeof(RE_FIBER)); if (fiber == NULL) return ERROR_INSUFFICIENT_MEMORY; fiber_pool->fiber_count++; } fiber->ip = NULL; fiber->sp = -1; fiber->rc = -1; fiber->next = NULL; fiber->prev = NULL; *new_fiber = fiber; return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Appends 'fiber' to 'fiber_list' // static void _yr_re_fiber_append(RE_FIBER_LIST* fiber_list, RE_FIBER* fiber) { assert(fiber->prev == NULL); assert(fiber->next == NULL); fiber->prev = fiber_list->tail; if (fiber_list->tail != NULL) fiber_list->tail->next = fiber; fiber_list->tail = fiber; if (fiber_list->head == NULL) fiber_list->head = fiber; assert(fiber_list->tail->next == NULL); assert(fiber_list->head->prev == NULL); } //////////////////////////////////////////////////////////////////////////////// // Verifies if a fiber with the same properties (ip, rc, sp, and stack values) // than 'target_fiber' exists in 'fiber_list'. The list is iterated from // the start until 'last_fiber' (inclusive). Fibers past 'last_fiber' are not // taken into account. // static int _yr_re_fiber_exists( RE_FIBER_LIST* fiber_list, RE_FIBER* target_fiber, RE_FIBER* last_fiber) { RE_FIBER* fiber = fiber_list->head; int equal_stacks; int i; if (last_fiber == NULL) return false; while (fiber != last_fiber->next) { if (fiber->ip == target_fiber->ip && fiber->sp == target_fiber->sp && fiber->rc == target_fiber->rc) { equal_stacks = true; for (i = 0; i <= fiber->sp; i++) { if (fiber->stack[i] != target_fiber->stack[i]) { equal_stacks = false; break; } } if (equal_stacks) return true; } fiber = fiber->next; } return false; } //////////////////////////////////////////////////////////////////////////////// // Clones a fiber in fiber_list and inserts the cloned fiber just after. // the original one. If fiber_list is: // // f1 -> f2 -> f3 -> f4 // // Splitting f2 will result in: // // f1 -> f2 -> cloned f2 -> f3 -> f4 // static int _yr_re_fiber_split( RE_FIBER_LIST* fiber_list, RE_FIBER_POOL* fiber_pool, RE_FIBER* fiber, RE_FIBER** new_fiber) { int32_t i; FAIL_ON_ERROR(_yr_re_fiber_create(fiber_pool, new_fiber)); (*new_fiber)->sp = fiber->sp; (*new_fiber)->ip = fiber->ip; (*new_fiber)->rc = fiber->rc; for (i = 0; i <= fiber->sp; i++) (*new_fiber)->stack[i] = fiber->stack[i]; (*new_fiber)->next = fiber->next; (*new_fiber)->prev = fiber; if (fiber->next != NULL) fiber->next->prev = *new_fiber; fiber->next = *new_fiber; if (fiber_list->tail == fiber) fiber_list->tail = *new_fiber; assert(fiber_list->tail->next == NULL); assert(fiber_list->head->prev == NULL); return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Kills a given fiber by removing it from the fiber list and putting it in the // fiber pool. // static RE_FIBER* _yr_re_fiber_kill( RE_FIBER_LIST* fiber_list, RE_FIBER_POOL* fiber_pool, RE_FIBER* fiber) { RE_FIBER* next_fiber = fiber->next; if (fiber->prev != NULL) fiber->prev->next = next_fiber; if (next_fiber != NULL) next_fiber->prev = fiber->prev; if (fiber_pool->fibers.tail != NULL) fiber_pool->fibers.tail->next = fiber; if (fiber_list->tail == fiber) fiber_list->tail = fiber->prev; if (fiber_list->head == fiber) fiber_list->head = next_fiber; fiber->next = NULL; fiber->prev = fiber_pool->fibers.tail; fiber_pool->fibers.tail = fiber; if (fiber_pool->fibers.head == NULL) fiber_pool->fibers.head = fiber; return next_fiber; } //////////////////////////////////////////////////////////////////////////////// // Kills all fibers from the given one up to the end of the fiber list. // static void _yr_re_fiber_kill_tail( RE_FIBER_LIST* fiber_list, RE_FIBER_POOL* fiber_pool, RE_FIBER* fiber) { RE_FIBER* prev_fiber = fiber->prev; if (prev_fiber != NULL) prev_fiber->next = NULL; fiber->prev = fiber_pool->fibers.tail; if (fiber_pool->fibers.tail != NULL) fiber_pool->fibers.tail->next = fiber; fiber_pool->fibers.tail = fiber_list->tail; fiber_list->tail = prev_fiber; if (fiber_list->head == fiber) fiber_list->head = NULL; if (fiber_pool->fibers.head == NULL) fiber_pool->fibers.head = fiber; } //////////////////////////////////////////////////////////////////////////////// // Kills all fibers in the fiber list. // static void _yr_re_fiber_kill_all( RE_FIBER_LIST* fiber_list, RE_FIBER_POOL* fiber_pool) { if (fiber_list->head != NULL) _yr_re_fiber_kill_tail(fiber_list, fiber_pool, fiber_list->head); } //////////////////////////////////////////////////////////////////////////////// // Executes a fiber until reaching an "matching" instruction. A "matching" // instruction is one that actually reads a byte from the input and performs // some matching. If the fiber reaches a split instruction, the new fiber is // also synced. // static int _yr_re_fiber_sync( RE_FIBER_LIST* fiber_list, RE_FIBER_POOL* fiber_pool, RE_FIBER* fiber_to_sync) { // A array for keeping track of which split instructions has been already // executed. Each split instruction within a regexp has an associated ID // between 0 and RE_MAX_SPLIT_ID-1. Keeping track of executed splits is // required to avoid infinite loops in regexps like (a*)* or (a|)* RE_SPLIT_ID_TYPE splits_executed[RE_MAX_SPLIT_ID]; RE_SPLIT_ID_TYPE splits_executed_count = 0; RE_SPLIT_ID_TYPE split_id, splits_executed_idx; int split_already_executed; RE_REPEAT_ARGS* repeat_args; RE_REPEAT_ANY_ARGS* repeat_any_args; RE_FIBER* fiber; RE_FIBER* last; RE_FIBER* next; RE_FIBER* branch_a; RE_FIBER* branch_b; fiber = fiber_to_sync; last = fiber_to_sync->next; while (fiber != last) { int16_t jmp_len; uint8_t opcode = *fiber->ip; switch (opcode) { case RE_OPCODE_SPLIT_A: case RE_OPCODE_SPLIT_B: split_id = *(RE_SPLIT_ID_TYPE*) (fiber->ip + 1); split_already_executed = false; for (splits_executed_idx = 0; splits_executed_idx < splits_executed_count; splits_executed_idx++) { if (split_id == splits_executed[splits_executed_idx]) { split_already_executed = true; break; } } if (split_already_executed) { fiber = _yr_re_fiber_kill(fiber_list, fiber_pool, fiber); } else { branch_a = fiber; FAIL_ON_ERROR( _yr_re_fiber_split(fiber_list, fiber_pool, branch_a, &branch_b)); // With RE_OPCODE_SPLIT_A the current fiber continues at the next // instruction in the stream (branch A), while the newly created // fiber starts at the address indicated by the instruction (branch B) // RE_OPCODE_SPLIT_B has the opposite behavior. if (opcode == RE_OPCODE_SPLIT_B) yr_swap(branch_a, branch_b, RE_FIBER*); // Branch A continues at the next instruction branch_a->ip += (sizeof(RE_SPLIT_ID_TYPE) + 3); // Branch B adds the offset indicated by the split instruction. jmp_len = yr_unaligned_i16(branch_b->ip + 1 + sizeof(RE_SPLIT_ID_TYPE)); branch_b->ip += jmp_len; #ifdef YR_PARANOID_MODE // In normal conditions this should never happen. But with compiled // rules that has been hand-crafted by a malicious actor this could // happen. if (splits_executed_count >= RE_MAX_SPLIT_ID) return ERROR_INTERNAL_FATAL_ERROR; #endif splits_executed[splits_executed_count] = split_id; splits_executed_count++; } break; case RE_OPCODE_REPEAT_START_GREEDY: case RE_OPCODE_REPEAT_START_UNGREEDY: repeat_args = (RE_REPEAT_ARGS*) (fiber->ip + 1); assert(repeat_args->max > 0); branch_a = fiber; if (repeat_args->min == 0) { FAIL_ON_ERROR( _yr_re_fiber_split(fiber_list, fiber_pool, branch_a, &branch_b)); if (opcode == RE_OPCODE_REPEAT_START_UNGREEDY) yr_swap(branch_a, branch_b, RE_FIBER*); branch_b->ip += repeat_args->offset; } branch_a->stack[++branch_a->sp] = 0; branch_a->ip += (1 + sizeof(RE_REPEAT_ARGS)); break; case RE_OPCODE_REPEAT_END_GREEDY: case RE_OPCODE_REPEAT_END_UNGREEDY: repeat_args = (RE_REPEAT_ARGS*) (fiber->ip + 1); fiber->stack[fiber->sp]++; if (fiber->stack[fiber->sp] < repeat_args->min) { fiber->ip += repeat_args->offset; break; } branch_a = fiber; if (fiber->stack[fiber->sp] < repeat_args->max) { FAIL_ON_ERROR( _yr_re_fiber_split(fiber_list, fiber_pool, branch_a, &branch_b)); if (opcode == RE_OPCODE_REPEAT_END_GREEDY) yr_swap(branch_a, branch_b, RE_FIBER*); branch_b->ip += repeat_args->offset; } branch_a->sp--; branch_a->ip += (1 + sizeof(RE_REPEAT_ARGS)); break; case RE_OPCODE_REPEAT_ANY_GREEDY: case RE_OPCODE_REPEAT_ANY_UNGREEDY: repeat_any_args = (RE_REPEAT_ANY_ARGS*) (fiber->ip + 1); // If repetition counter (rc) is -1 it means that we are reaching this // instruction from the previous one in the instructions stream. In // this case let's initialize the counter to 0 and start looping. if (fiber->rc == -1) fiber->rc = 0; if (fiber->rc < repeat_any_args->min) { // Increase repetition counter and continue with next fiber. The // instruction pointer for this fiber is not incremented yet, this // fiber spins in this same instruction until reaching the minimum // number of repetitions. fiber->rc++; fiber = fiber->next; } else if (fiber->rc < repeat_any_args->max) { // Once the minimum number of repetitions are matched one fiber // remains spinning in this instruction until reaching the maximum // number of repetitions while new fibers are created. New fibers // start executing at the next instruction. next = fiber->next; branch_a = fiber; FAIL_ON_ERROR( _yr_re_fiber_split(fiber_list, fiber_pool, branch_a, &branch_b)); if (opcode == RE_OPCODE_REPEAT_ANY_UNGREEDY) yr_swap(branch_a, branch_b, RE_FIBER*); branch_a->rc++; branch_b->ip += (1 + sizeof(RE_REPEAT_ANY_ARGS)); branch_b->rc = -1; FAIL_ON_ERROR(_yr_re_fiber_sync(fiber_list, fiber_pool, branch_b)); fiber = next; } else { // When the maximum number of repetitions is reached the fiber keeps // executing at the next instruction. The repetition counter is set // to -1 indicating that we are not spinning in a repeat instruction // anymore. fiber->ip += (1 + sizeof(RE_REPEAT_ANY_ARGS)); fiber->rc = -1; } break; case RE_OPCODE_JUMP: jmp_len = yr_unaligned_i16(fiber->ip + 1); fiber->ip += jmp_len; break; default: fiber = fiber->next; } } return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Executes a regular expression. The specified regular expression will try to // match the data starting at the address specified by "input". The "input" // pointer can point to any address inside a memory buffer. Arguments // "input_forwards_size" and "input_backwards_size" indicate how many bytes // can be accessible starting at "input" and going forwards and backwards // respectively. // // <--- input_backwards_size -->|<----------- input_forwards_size --------> // |-------- memory buffer -----------------------------------------------| // ^ // input // // Args: // YR_SCAN_CONTEXT *context - Scan context. // const uint8_t* code - Regexp code be executed // const uint8_t* input - Pointer to input data // size_t input_forwards_size - Number of accessible bytes starting at // "input" and going forwards. // size_t input_backwards_size - Number of accessible bytes starting at // "input" and going backwards // int flags - Flags: // RE_FLAGS_SCAN // RE_FLAGS_BACKWARDS // RE_FLAGS_EXHAUSTIVE // RE_FLAGS_WIDE // RE_FLAGS_NO_CASE // RE_FLAGS_DOT_ALL // RE_MATCH_CALLBACK_FUNC callback - Callback function // void* callback_args - Callback argument // int* matches - Pointer to an integer receiving the // number of matching bytes. Notice that // 0 means a zero-length match, while no // matches is -1. // Returns: // ERROR_SUCCESS or any other error code. int yr_re_exec( YR_SCAN_CONTEXT* context, const uint8_t* code, const uint8_t* input_data, size_t input_forwards_size, size_t input_backwards_size, int flags, RE_MATCH_CALLBACK_FUNC callback, void* callback_args, int* matches) { const uint8_t* input; const uint8_t* ip; uint16_t opcode_args; uint8_t mask; uint8_t value; uint8_t character_size; RE_FIBER_LIST fibers; RE_FIBER* fiber; RE_FIBER* next_fiber; int bytes_matched; int max_bytes_matched; int match; int input_incr; int kill; int action; bool prev_is_word_char = false; bool input_is_word_char = false; #define ACTION_NONE 0 #define ACTION_CONTINUE 1 #define ACTION_KILL 2 #define ACTION_KILL_TAIL 3 #define prolog \ { \ if ((bytes_matched >= max_bytes_matched) || \ (character_size == 2 && *(input + 1) != 0)) \ { \ action = ACTION_KILL; \ break; \ } \ } if (matches != NULL) *matches = -1; if (flags & RE_FLAGS_WIDE) character_size = 2; else character_size = 1; input = input_data; input_incr = character_size; if (flags & RE_FLAGS_BACKWARDS) { // Signedness conversion is sound as long as YR_RE_SCAN_LIMIT <= INT_MAX max_bytes_matched = (int) yr_min(input_backwards_size, YR_RE_SCAN_LIMIT); input -= character_size; input_incr = -input_incr; } else { // Signedness conversion is sound as long as YR_RE_SCAN_LIMIT <= INT_MAX max_bytes_matched = (int) yr_min(input_forwards_size, YR_RE_SCAN_LIMIT); } // Round down max_bytes_matched to a multiple of character_size, this way if // character_size is 2 and max_bytes_matched is odd we are ignoring the // extra byte which can't match anyways. max_bytes_matched = max_bytes_matched - max_bytes_matched % character_size; bytes_matched = 0; FAIL_ON_ERROR(_yr_re_fiber_create(&context->re_fiber_pool, &fiber)); fiber->ip = code; fibers.head = fiber; fibers.tail = fiber; FAIL_ON_ERROR_WITH_CLEANUP( _yr_re_fiber_sync(&fibers, &context->re_fiber_pool, fiber), _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); while (fibers.head != NULL) { fiber = fibers.head; while (fiber != NULL) { next_fiber = fiber->next; if (_yr_re_fiber_exists(&fibers, fiber, fiber->prev)) _yr_re_fiber_kill(&fibers, &context->re_fiber_pool, fiber); fiber = next_fiber; } fiber = fibers.head; while (fiber != NULL) { ip = fiber->ip; action = ACTION_NONE; switch (*ip) { case RE_OPCODE_ANY: prolog; match = (flags & RE_FLAGS_DOT_ALL) || (*input != 0x0A); action = match ? ACTION_NONE : ACTION_KILL; fiber->ip += 1; break; case RE_OPCODE_REPEAT_ANY_GREEDY: case RE_OPCODE_REPEAT_ANY_UNGREEDY: prolog; match = (flags & RE_FLAGS_DOT_ALL) || (*input != 0x0A); action = match ? ACTION_NONE : ACTION_KILL; // The instruction pointer is not incremented here. The current fiber // spins in this instruction until reaching the required number of // repetitions. The code controlling the number of repetitions is in // _yr_re_fiber_sync. break; case RE_OPCODE_LITERAL: prolog; if (flags & RE_FLAGS_NO_CASE) match = yr_lowercase[*input] == yr_lowercase[*(ip + 1)]; else match = (*input == *(ip + 1)); action = match ? ACTION_NONE : ACTION_KILL; fiber->ip += 2; break; case RE_OPCODE_NOT_LITERAL: prolog; // We don't need to take into account the case-insensitive // case because this opcode is only used with hex strings, // which can't be case-insensitive. match = (*input != *(ip + 1)); action = match ? ACTION_NONE : ACTION_KILL; fiber->ip += 2; break; case RE_OPCODE_MASKED_LITERAL: prolog; opcode_args = yr_unaligned_u16(ip + 1); mask = opcode_args >> 8; value = opcode_args & 0xFF; // We don't need to take into account the case-insensitive // case because this opcode is only used with hex strings, // which can't be case-insensitive. match = ((*input & mask) == value); action = match ? ACTION_NONE : ACTION_KILL; fiber->ip += 3; break; case RE_OPCODE_MASKED_NOT_LITERAL: prolog; opcode_args = yr_unaligned_u16(ip + 1); mask = opcode_args >> 8; value = opcode_args & 0xFF; // We don't need to take into account the case-insensitive // case because this opcode is only used with hex strings, // which can't be case-insensitive. match = ((*input & mask) != value); action = match ? ACTION_NONE : ACTION_KILL; fiber->ip += 3; break; case RE_OPCODE_CLASS: prolog; match = _yr_re_is_char_in_class( (RE_CLASS*) (ip + 1), *input, flags & RE_FLAGS_NO_CASE); action = match ? ACTION_NONE : ACTION_KILL; fiber->ip += (sizeof(RE_CLASS) + 1); break; case RE_OPCODE_WORD_CHAR: prolog; match = _yr_re_is_word_char(input, character_size); action = match ? ACTION_NONE : ACTION_KILL; fiber->ip += 1; break; case RE_OPCODE_NON_WORD_CHAR: prolog; match = !_yr_re_is_word_char(input, character_size); action = match ? ACTION_NONE : ACTION_KILL; fiber->ip += 1; break; case RE_OPCODE_SPACE: case RE_OPCODE_NON_SPACE: prolog; switch (*input) { case ' ': case '\t': case '\r': case '\n': case '\v': case '\f': match = true; break; default: match = false; } if (*ip == RE_OPCODE_NON_SPACE) match = !match; action = match ? ACTION_NONE : ACTION_KILL; fiber->ip += 1; break; case RE_OPCODE_DIGIT: prolog; match = isdigit(*input); action = match ? ACTION_NONE : ACTION_KILL; fiber->ip += 1; break; case RE_OPCODE_NON_DIGIT: prolog; match = !isdigit(*input); action = match ? ACTION_NONE : ACTION_KILL; fiber->ip += 1; break; case RE_OPCODE_WORD_BOUNDARY: case RE_OPCODE_NON_WORD_BOUNDARY: if (input - input_incr + character_size <= input_data + input_forwards_size && input - input_incr >= input_data - input_backwards_size) { prev_is_word_char = _yr_re_is_word_char( input - input_incr, character_size); } else { prev_is_word_char = false; } if (input + character_size <= input_data + input_forwards_size && input >= input_data - input_backwards_size) { input_is_word_char = _yr_re_is_word_char(input, character_size); } else { input_is_word_char = false; } match = (prev_is_word_char && !input_is_word_char) || (!prev_is_word_char && input_is_word_char); if (*ip == RE_OPCODE_NON_WORD_BOUNDARY) match = !match; action = match ? ACTION_CONTINUE : ACTION_KILL; fiber->ip += 1; break; case RE_OPCODE_MATCH_AT_START: if (flags & RE_FLAGS_BACKWARDS) kill = input_backwards_size > (size_t) bytes_matched; else kill = input_backwards_size > 0 || (bytes_matched != 0); action = kill ? ACTION_KILL : ACTION_CONTINUE; fiber->ip += 1; break; case RE_OPCODE_MATCH_AT_END: kill = flags & RE_FLAGS_BACKWARDS || input_forwards_size > (size_t) bytes_matched; action = kill ? ACTION_KILL : ACTION_CONTINUE; fiber->ip += 1; break; case RE_OPCODE_MATCH: if (matches != NULL) *matches = bytes_matched; if (flags & RE_FLAGS_EXHAUSTIVE) { if (callback != NULL) { if (flags & RE_FLAGS_BACKWARDS) { FAIL_ON_ERROR_WITH_CLEANUP( callback( input + character_size, bytes_matched, flags, callback_args), _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); } else { FAIL_ON_ERROR_WITH_CLEANUP( callback(input_data, bytes_matched, flags, callback_args), _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); } } action = ACTION_KILL; } else { action = ACTION_KILL_TAIL; } break; default: assert(false); } switch (action) { case ACTION_KILL: fiber = _yr_re_fiber_kill(&fibers, &context->re_fiber_pool, fiber); break; case ACTION_KILL_TAIL: _yr_re_fiber_kill_tail(&fibers, &context->re_fiber_pool, fiber); fiber = NULL; break; case ACTION_CONTINUE: FAIL_ON_ERROR_WITH_CLEANUP( _yr_re_fiber_sync(&fibers, &context->re_fiber_pool, fiber), _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); break; default: next_fiber = fiber->next; FAIL_ON_ERROR_WITH_CLEANUP( _yr_re_fiber_sync(&fibers, &context->re_fiber_pool, fiber), _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); fiber = next_fiber; } } input += input_incr; bytes_matched += character_size; if (flags & RE_FLAGS_SCAN && bytes_matched < max_bytes_matched) { FAIL_ON_ERROR_WITH_CLEANUP( _yr_re_fiber_create(&context->re_fiber_pool, &fiber), _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); fiber->ip = code; _yr_re_fiber_append(&fibers, fiber); FAIL_ON_ERROR_WITH_CLEANUP( _yr_re_fiber_sync(&fibers, &context->re_fiber_pool, fiber), _yr_re_fiber_kill_all(&fibers, &context->re_fiber_pool)); } } return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Helper function that creates a RE_FAST_EXEC_POSITION by either allocating it // or reusing a previously allocated one from a pool. // static int _yr_re_fast_exec_position_create( RE_FAST_EXEC_POSITION_POOL* pool, RE_FAST_EXEC_POSITION** new_position) { RE_FAST_EXEC_POSITION* position; if (pool->head != NULL) { position = pool->head; pool->head = position->next; } else { position = (RE_FAST_EXEC_POSITION*) yr_malloc( sizeof(RE_FAST_EXEC_POSITION)); if (position == NULL) return ERROR_INSUFFICIENT_MEMORY; } position->input = NULL; position->round = 0; position->next = NULL; position->prev = NULL; *new_position = position; return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Helper function that moves a list of RE_FAST_EXEC_POSITION structures to a // pool represented by a RE_FAST_EXEC_POSITION_POOL. Receives pointers to the // pool, the first item, and last item in the list. // static void _yr_re_fast_exec_destroy_position_list( RE_FAST_EXEC_POSITION_POOL* pool, RE_FAST_EXEC_POSITION* first, RE_FAST_EXEC_POSITION* last) { last->next = pool->head; if (pool->head != NULL) pool->head->prev = last; pool->head = first; } //////////////////////////////////////////////////////////////////////////////// // This function replaces yr_re_exec for regular expressions marked with flag // RE_FLAGS_FAST_REGEXP. These regular expressions are derived from hex strings // that don't contain alternatives, like for example: // // { 01 02 03 04 [0-2] 04 05 06 07 } // // The regexp's code produced by such strings can be matched by a faster, less // general algorithm, and it contains only the following opcodes: // // * RE_OPCODE_LITERAL // * RE_OPCODE_MASKED_LITERAL, // * RE_OPCODE_NOT_LITERAL // * RE_OPCODE_MASKED_NOT_LITERAL // * RE_OPCODE_ANY // * RE_OPCODE_REPEAT_ANY_UNGREEDY // * RE_OPCODE_MATCH. // // The regexp's code is executed one instruction at time, and the function // maintains a list of positions within the input for tracking different // matching alternatives, these positions are described by an instance of // RE_FAST_EXEC_POSITION. With each instruction the list of positions is // updated, removing those where the input data doesn't match the current // instruction, or adding new positions if the instruction is // RE_OPCODE_REPEAT_ANY_UNGREEDY. The list of positions is maintained sorted // by the value of the pointer they hold to the input, and it doesn't contain // duplicated pointer values. // int yr_re_fast_exec( YR_SCAN_CONTEXT* context, const uint8_t* code, const uint8_t* input_data, size_t input_forwards_size, size_t input_backwards_size, int flags, RE_MATCH_CALLBACK_FUNC callback, void* callback_args, int* matches) { RE_REPEAT_ANY_ARGS* repeat_any_args; // Pointers to the first and last position in the list. RE_FAST_EXEC_POSITION* first; RE_FAST_EXEC_POSITION* last; int input_incr = flags & RE_FLAGS_BACKWARDS ? -1 : 1; int bytes_matched; int max_bytes_matched; if (flags & RE_FLAGS_BACKWARDS) max_bytes_matched = (int) yr_min(input_backwards_size, YR_RE_SCAN_LIMIT); else max_bytes_matched = (int) yr_min(input_forwards_size, YR_RE_SCAN_LIMIT); const uint8_t* ip = code; // Create the first position in the list, which points to the start of the // input data. Intially this is the only position, more positions will be // created every time RE_OPCODE_REPEAT_ANY_UNGREEDY is executed. FAIL_ON_ERROR(_yr_re_fast_exec_position_create( &context->re_fast_exec_position_pool, &first)); first->round = 0; first->input = input_data; first->prev = NULL; first->next = NULL; if (flags & RE_FLAGS_BACKWARDS) first->input--; // As we are starting with a single position, the last one and the first one // are the same. last = first; // Round is incremented with every regxp instruction. int round = 0; // Keep in the loop until the list of positions gets empty. Positions are // removed from the list when they don't match the current instruction in // the code. while (first != NULL) { RE_FAST_EXEC_POSITION* current = first; // Iterate over all the positions, executing the current instruction at // all of them. while (current != NULL) { RE_FAST_EXEC_POSITION* next = current->next; // Ignore any position in the list whose round number is different from // the current round. This prevents new positions added to the list in // this round from being taken into account in this same round. if (current->round != round) { current = next; continue; } bytes_matched = flags & RE_FLAGS_BACKWARDS ? (int) (input_data - current->input - 1) : (int) (current->input - input_data); uint16_t opcode_args; uint8_t mask; uint8_t value; bool match = false; switch (*ip) { case RE_OPCODE_ANY: if (bytes_matched >= max_bytes_matched) break; match = true; current->input += input_incr; break; case RE_OPCODE_LITERAL: if (bytes_matched >= max_bytes_matched) break; if (*current->input == *(ip + 1)) { match = true; current->input += input_incr; } break; case RE_OPCODE_NOT_LITERAL: if (bytes_matched >= max_bytes_matched) break; if (*current->input != *(ip + 1)) { match = true; current->input += input_incr; } break; case RE_OPCODE_MASKED_LITERAL: if (bytes_matched >= max_bytes_matched) break; opcode_args = yr_unaligned_u16(ip + 1); mask = opcode_args >> 8; value = opcode_args & 0xFF; if ((*current->input & mask) == value) { match = true; current->input += input_incr; } break; case RE_OPCODE_MASKED_NOT_LITERAL: if (bytes_matched >= max_bytes_matched) break; opcode_args = yr_unaligned_u16(ip + 1); mask = opcode_args >> 8; value = opcode_args & 0xFF; if ((*current->input & mask) != value) { match = true; current->input += input_incr; } break; case RE_OPCODE_REPEAT_ANY_UNGREEDY: repeat_any_args = (RE_REPEAT_ANY_ARGS*) (ip + 1); if (bytes_matched + repeat_any_args->min >= max_bytes_matched) break; match = true; const uint8_t* next_opcode = ip + 1 + sizeof(RE_REPEAT_ANY_ARGS); // insertion_point indicates the item in the list of inputs after which // the newly created inputs will be inserted. RE_FAST_EXEC_POSITION* insertion_point = current; for (int j = repeat_any_args->min + 1; j <= repeat_any_args->max; j++) { // bytes_matched is the number of bytes matched so far, and j is the // minimum number of bytes that are still pending to match. If these // two numbers sum more than the maximum number of bytes that can be // matched the loop can be aborted. The position that we were about // to create can't lead to a match without exceeding // max_bytes_matched. if (bytes_matched + j >= max_bytes_matched) break; const uint8_t* next_input = current->input + j * input_incr; // Find the point where next_input should be inserted. The list is // kept sorted by pointer in increasing order, the insertion point is // an item that has a pointer lower or equal than next_input, but // whose next item have a pointer that is larger. while (insertion_point->next != NULL && insertion_point->next->input <= next_input) { insertion_point = insertion_point->next; } // If the input already exists for the next round, we don't need to // insert it. if (insertion_point->round == round + 1 && insertion_point->input == next_input) continue; // The next opcode is RE_OPCODE_LITERAL, but the literal doesn't // match with the byte at next_input, we don't need to add this // input to the list as we already know that it won't match in the // next round and will be deleted from the list anyways. if (*(next_opcode) == RE_OPCODE_LITERAL && *(next_opcode + 1) != *next_input) continue; RE_FAST_EXEC_POSITION* new_input; FAIL_ON_ERROR_WITH_CLEANUP( _yr_re_fast_exec_position_create( &context->re_fast_exec_position_pool, &new_input), // Cleanup _yr_re_fast_exec_destroy_position_list( &context->re_fast_exec_position_pool, first, last)); new_input->input = next_input; new_input->round = round + 1; new_input->prev = insertion_point; new_input->next = insertion_point->next; insertion_point->next = new_input; if (new_input->next != NULL) new_input->next->prev = new_input; if (insertion_point == last) last = new_input; } current->input += input_incr * repeat_any_args->min; break; case RE_OPCODE_MATCH: if (flags & RE_FLAGS_EXHAUSTIVE) { FAIL_ON_ERROR_WITH_CLEANUP( callback( // When matching forwards the matching data always starts at // input_data, when matching backwards it starts at input + 1 // or input_data - input_backwards_size if input + 1 is // outside the buffer. flags & RE_FLAGS_BACKWARDS ? yr_max( current->input + 1, input_data - input_backwards_size) : input_data, // The number of matched bytes should not be larger than // max_bytes_matched. yr_min(bytes_matched, max_bytes_matched), flags, callback_args), // Cleanup _yr_re_fast_exec_destroy_position_list( &context->re_fast_exec_position_pool, first, last)); } else { if (matches != NULL) *matches = bytes_matched; _yr_re_fast_exec_destroy_position_list( &context->re_fast_exec_position_pool, first, last); return ERROR_SUCCESS; } break; default: printf("non-supported opcode: %d\n", *ip); assert(false); } if (match) { current->round = round + 1; } else { // Remove current from the list. If the item being removed is the first // one or the last one, the first and last pointers should be updated. // The removed item is put into the pool for later reuse. if (current == first) first = current->next; if (current == last) last = current->prev; if (current->prev != NULL) current->prev->next = current->next; if (current->next != NULL) current->next->prev = current->prev; current->prev = NULL; current->next = context->re_fast_exec_position_pool.head; if (current->next != NULL) current->next->prev = current; context->re_fast_exec_position_pool.head = current; } current = next; } // while (current != NULL) // Move instruction pointer (ip) to next instruction. Each opcode has // a different size. switch (*ip) { case RE_OPCODE_ANY: ip += 1; break; case RE_OPCODE_LITERAL: case RE_OPCODE_NOT_LITERAL: ip += 2; break; case RE_OPCODE_MASKED_LITERAL: case RE_OPCODE_MASKED_NOT_LITERAL: ip += 3; break; case RE_OPCODE_REPEAT_ANY_UNGREEDY: ip += 1 + sizeof(RE_REPEAT_ANY_ARGS); break; case RE_OPCODE_MATCH: break; default: assert(false); } round++; } // If this point is reached no matches were found. if (matches != NULL) *matches = -1; return ERROR_SUCCESS; } static void _yr_re_print_node(RE_NODE* re_node, uint32_t indent) { RE_NODE* child; int i; if (re_node == NULL) return; if (indent > 0) printf("\n%*s", indent, " "); switch (re_node->type) { case RE_NODE_ALT: printf("Alt("); _yr_re_print_node(re_node->children_head, indent + 4); printf(","); _yr_re_print_node(re_node->children_tail, indent + 4); printf("\n%*s%s", indent, " ", ")"); break; case RE_NODE_CONCAT: printf("Cat("); child = re_node->children_head; while (child != NULL) { _yr_re_print_node(child, indent + 4); printf(","); child = child->next_sibling; } printf("\n%*s%s", indent, " ", ")"); break; case RE_NODE_STAR: printf("Star("); _yr_re_print_node(re_node->children_head, indent + 4); printf(")"); break; case RE_NODE_PLUS: printf("Plus("); _yr_re_print_node(re_node->children_head, indent + 4); printf(")"); break; case RE_NODE_LITERAL: printf("Lit(%c)", re_node->value); break; case RE_NODE_NOT_LITERAL: printf("NotLit(%c)", re_node->value); break; case RE_NODE_MASKED_LITERAL: printf("MaskedLit(%02X,%02X)", re_node->value, re_node->mask); break; case RE_NODE_WORD_CHAR: printf("WordChar"); break; case RE_NODE_NON_WORD_CHAR: printf("NonWordChar"); break; case RE_NODE_SPACE: printf("Space"); break; case RE_NODE_NON_SPACE: printf("NonSpace"); break; case RE_NODE_DIGIT: printf("Digit"); break; case RE_NODE_NON_DIGIT: printf("NonDigit"); break; case RE_NODE_ANY: printf("Any"); break; case RE_NODE_RANGE: printf("Range(%d-%d, ", re_node->start, re_node->end); _yr_re_print_node(re_node->children_head, indent + 4); printf("\n%*s%s", indent, " ", ")"); break; case RE_NODE_CLASS: printf("Class("); for (i = 0; i < 256; i++) if (_yr_re_is_char_in_class(re_node->re_class, i, false)) printf("%02X,", i); printf(")"); break; case RE_NODE_EMPTY: printf("Empty"); break; case RE_NODE_ANCHOR_START: printf("AnchorStart"); break; case RE_NODE_ANCHOR_END: printf("AnchorEnd"); break; case RE_NODE_WORD_BOUNDARY: printf("WordBoundary"); break; case RE_NODE_NON_WORD_BOUNDARY: printf("NonWordBoundary"); break; case RE_NODE_RANGE_ANY: printf("RangeAny"); break; default: printf("???"); break; } } void yr_re_print(RE_AST* re_ast) { _yr_re_print_node(re_ast->root_node, 0); } yara-4.5.3/libyara/re_grammar.c000066400000000000000000001631401501365277300164000ustar00rootroot00000000000000/* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. 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 . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output, and Bison version. */ #define YYBISON 30802 /* Bison version string. */ #define YYBISON_VERSION "3.8.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 1 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Substitute the variable and function names. */ #define yyparse re_yyparse #define yylex re_yylex #define yyerror re_yyerror #define yydebug re_yydebug #define yynerrs re_yynerrs /* First part of user prologue. */ #line 32 "re_grammar.y" #include #include #include #include #include #include #include #define YYERROR_VERBOSE #define YYMALLOC yr_malloc #define YYFREE yr_free #define mark_as_not_fast_regexp() \ ((RE_AST*) yyget_extra(yyscanner))->flags &= ~RE_FLAGS_FAST_REGEXP #define fail_if(x, error) \ if (x) \ { \ lex_env->last_error = error; \ YYABORT; \ } \ #define destroy_node_if(x, node) \ if (x) \ { \ yr_re_node_destroy(node); \ } \ #line 110 "re_grammar.c" # ifndef YY_CAST # ifdef __cplusplus # define YY_CAST(Type, Val) static_cast (Val) # define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) # else # define YY_CAST(Type, Val) ((Type) (Val)) # define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) # endif # endif # ifndef YY_NULLPTR # if defined __cplusplus # if 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # else # define YY_NULLPTR ((void*)0) # endif # endif /* Use api.header.include to #include this header instead of duplicating it here. */ #ifndef YY_RE_YY_RE_GRAMMAR_H_INCLUDED # define YY_RE_YY_RE_GRAMMAR_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int re_yydebug; #endif /* Token kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, YYEOF = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ _CHAR_ = 258, /* _CHAR_ */ _ANY_ = 259, /* _ANY_ */ _RANGE_ = 260, /* _RANGE_ */ _CLASS_ = 261, /* _CLASS_ */ _WORD_CHAR_ = 262, /* _WORD_CHAR_ */ _NON_WORD_CHAR_ = 263, /* _NON_WORD_CHAR_ */ _SPACE_ = 264, /* _SPACE_ */ _NON_SPACE_ = 265, /* _NON_SPACE_ */ _DIGIT_ = 266, /* _DIGIT_ */ _NON_DIGIT_ = 267, /* _NON_DIGIT_ */ _WORD_BOUNDARY_ = 268, /* _WORD_BOUNDARY_ */ _NON_WORD_BOUNDARY_ = 269 /* _NON_WORD_BOUNDARY_ */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Token kinds. */ #define YYEMPTY -2 #define YYEOF 0 #define YYerror 256 #define YYUNDEF 257 #define _CHAR_ 258 #define _ANY_ 259 #define _RANGE_ 260 #define _CLASS_ 261 #define _WORD_CHAR_ 262 #define _NON_WORD_CHAR_ 263 #define _SPACE_ 264 #define _NON_SPACE_ 265 #define _DIGIT_ 266 #define _NON_DIGIT_ 267 #define _WORD_BOUNDARY_ 268 #define _NON_WORD_BOUNDARY_ 269 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 75 "re_grammar.y" int integer; uint32_t range; RE_NODE* re_node; RE_CLASS* re_class; #line 198 "re_grammar.c" }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif int re_yyparse (void *yyscanner, RE_LEX_ENVIRONMENT *lex_env); #endif /* !YY_RE_YY_RE_GRAMMAR_H_INCLUDED */ /* Symbol kind. */ enum yysymbol_kind_t { YYSYMBOL_YYEMPTY = -2, YYSYMBOL_YYEOF = 0, /* "end of file" */ YYSYMBOL_YYerror = 1, /* error */ YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ YYSYMBOL__CHAR_ = 3, /* _CHAR_ */ YYSYMBOL__ANY_ = 4, /* _ANY_ */ YYSYMBOL__RANGE_ = 5, /* _RANGE_ */ YYSYMBOL__CLASS_ = 6, /* _CLASS_ */ YYSYMBOL__WORD_CHAR_ = 7, /* _WORD_CHAR_ */ YYSYMBOL__NON_WORD_CHAR_ = 8, /* _NON_WORD_CHAR_ */ YYSYMBOL__SPACE_ = 9, /* _SPACE_ */ YYSYMBOL__NON_SPACE_ = 10, /* _NON_SPACE_ */ YYSYMBOL__DIGIT_ = 11, /* _DIGIT_ */ YYSYMBOL__NON_DIGIT_ = 12, /* _NON_DIGIT_ */ YYSYMBOL__WORD_BOUNDARY_ = 13, /* _WORD_BOUNDARY_ */ YYSYMBOL__NON_WORD_BOUNDARY_ = 14, /* _NON_WORD_BOUNDARY_ */ YYSYMBOL_15_ = 15, /* '|' */ YYSYMBOL_16_ = 16, /* '*' */ YYSYMBOL_17_ = 17, /* '?' */ YYSYMBOL_18_ = 18, /* '+' */ YYSYMBOL_19_ = 19, /* '^' */ YYSYMBOL_20_ = 20, /* '$' */ YYSYMBOL_21_ = 21, /* '(' */ YYSYMBOL_22_ = 22, /* ')' */ YYSYMBOL_23_ = 23, /* '.' */ YYSYMBOL_YYACCEPT = 24, /* $accept */ YYSYMBOL_re = 25, /* re */ YYSYMBOL_alternative = 26, /* alternative */ YYSYMBOL_concatenation = 27, /* concatenation */ YYSYMBOL_repeat = 28, /* repeat */ YYSYMBOL_single = 29 /* single */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; #ifdef short # undef short #endif /* On compilers that do not define __PTRDIFF_MAX__ etc., make sure and (if available) are included so that the code can choose integer types of a good width. */ #ifndef __PTRDIFF_MAX__ # include /* INFRINGES ON USER NAME SPACE */ # if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YY_STDINT_H # endif #endif /* Narrow types that promote to a signed type and that can represent a signed or unsigned integer of at least N bits. In tables they can save space and decrease cache pressure. Promoting to a signed type helps avoid bugs in integer arithmetic. */ #ifdef __INT_LEAST8_MAX__ typedef __INT_LEAST8_TYPE__ yytype_int8; #elif defined YY_STDINT_H typedef int_least8_t yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef __INT_LEAST16_MAX__ typedef __INT_LEAST16_TYPE__ yytype_int16; #elif defined YY_STDINT_H typedef int_least16_t yytype_int16; #else typedef short yytype_int16; #endif /* Work around bug in HP-UX 11.23, which defines these macros incorrectly for preprocessor constants. This workaround can likely be removed in 2023, as HPE has promised support for HP-UX 11.23 (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of . */ #ifdef __hpux # undef UINT_LEAST8_MAX # undef UINT_LEAST16_MAX # define UINT_LEAST8_MAX 255 # define UINT_LEAST16_MAX 65535 #endif #if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ typedef __UINT_LEAST8_TYPE__ yytype_uint8; #elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ && UINT_LEAST8_MAX <= INT_MAX) typedef uint_least8_t yytype_uint8; #elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX typedef unsigned char yytype_uint8; #else typedef short yytype_uint8; #endif #if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ typedef __UINT_LEAST16_TYPE__ yytype_uint16; #elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ && UINT_LEAST16_MAX <= INT_MAX) typedef uint_least16_t yytype_uint16; #elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX typedef unsigned short yytype_uint16; #else typedef int yytype_uint16; #endif #ifndef YYPTRDIFF_T # if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ # define YYPTRDIFF_T __PTRDIFF_TYPE__ # define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ # elif defined PTRDIFF_MAX # ifndef ptrdiff_t # include /* INFRINGES ON USER NAME SPACE */ # endif # define YYPTRDIFF_T ptrdiff_t # define YYPTRDIFF_MAXIMUM PTRDIFF_MAX # else # define YYPTRDIFF_T long # define YYPTRDIFF_MAXIMUM LONG_MAX # endif #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned # endif #endif #define YYSIZE_MAXIMUM \ YY_CAST (YYPTRDIFF_T, \ (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ ? YYPTRDIFF_MAXIMUM \ : YY_CAST (YYSIZE_T, -1))) #define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) /* Stored state numbers (used for stacks). */ typedef yytype_int8 yy_state_t; /* State numbers in computations. */ typedef int yy_state_fast_t; #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE_PURE # if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) # else # define YY_ATTRIBUTE_PURE # endif #endif #ifndef YY_ATTRIBUTE_UNUSED # if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) # define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) # else # define YY_ATTRIBUTE_UNUSED # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YY_USE(E) ((void) (E)) #else # define YY_USE(E) /* empty */ #endif /* Suppress an incorrect diagnostic about yylval being uninitialized. */ #if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ # if __GNUC__ * 100 + __GNUC_MINOR__ < 407 # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") # else # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # endif # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ # define YY_IGNORE_USELESS_CAST_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") # define YY_IGNORE_USELESS_CAST_END \ _Pragma ("GCC diagnostic pop") #endif #ifndef YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_BEGIN # define YY_IGNORE_USELESS_CAST_END #endif #define YY_ASSERT(E) ((void) (0 && (E))) #if !defined yyoverflow /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* !defined yyoverflow */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yy_state_t yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYPTRDIFF_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / YYSIZEOF (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYPTRDIFF_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 22 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 45 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 24 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 6 /* YYNRULES -- Number of rules. */ #define YYNRULES 31 /* YYNSTATES -- Number of states. */ #define YYNSTATES 35 /* YYMAXUTOK -- Last valid token kind. */ #define YYMAXUTOK 269 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM as returned by yylex, with out-of-bounds checking. */ #define YYTRANSLATE(YYX) \ (0 <= (YYX) && (YYX) <= YYMAXUTOK \ ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ : YYSYMBOL_YYUNDEF) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex. */ static const yytype_int8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 20, 2, 2, 2, 21, 22, 16, 18, 2, 2, 23, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 17, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 19, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { 0, 106, 106, 111, 115, 119, 133, 157, 166, 174, 190, 208, 224, 241, 264, 288, 311, 335, 339, 345, 351, 357, 366, 370, 379, 388, 394, 400, 406, 412, 418, 424 }; #endif /** Accessing symbol of state STATE. */ #define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) #if YYDEBUG || 0 /* The user-facing name of the symbol whose (internal) number is YYSYMBOL. No bounds checking. */ static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "\"end of file\"", "error", "\"invalid token\"", "_CHAR_", "_ANY_", "_RANGE_", "_CLASS_", "_WORD_CHAR_", "_NON_WORD_CHAR_", "_SPACE_", "_NON_SPACE_", "_DIGIT_", "_NON_DIGIT_", "_WORD_BOUNDARY_", "_NON_WORD_BOUNDARY_", "'|'", "'*'", "'?'", "'+'", "'^'", "'$'", "'('", "')'", "'.'", "$accept", "re", "alternative", "concatenation", "repeat", "single", YY_NULLPTR }; static const char * yysymbol_name (yysymbol_kind_t yysymbol) { return yytname[yysymbol]; } #endif #define YYPACT_NINF (-12) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) #define YYTABLE_NINF (-1) #define yytable_value_is_error(Yyn) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int8 yypact[] = { -1, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, 18, -12, 1, -11, 18, -12, -2, 21, -12, 18, -12, 0, 16, 17, 23, -12, 18, -12, -12, -12, -12 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_int8 yydefact[] = { 0, 3, 24, 31, 25, 26, 27, 28, 29, 30, 18, 19, 20, 21, 0, 23, 0, 2, 4, 7, 17, 0, 1, 6, 8, 15, 9, 13, 11, 22, 5, 16, 10, 14, 12 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -12, -12, 28, 22, 5, -12 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { 0, 16, 17, 18, 19, 20 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int8 yytable[] = { 1, 22, 2, 25, 23, 3, 4, 5, 6, 7, 8, 9, 10, 11, 26, 27, 28, 31, 12, 13, 14, 2, 15, 24, 3, 4, 5, 6, 7, 8, 9, 10, 11, 32, 33, 24, 23, 12, 13, 14, 34, 15, 21, 29, 0, 30 }; static const yytype_int8 yycheck[] = { 1, 0, 3, 5, 15, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 17, 19, 20, 21, 3, 23, 18, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 17, 30, 15, 19, 20, 21, 17, 23, 14, 22, -1, 23 }; /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of state STATE-NUM. */ static const yytype_int8 yystos[] = { 0, 1, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 19, 20, 21, 23, 25, 26, 27, 28, 29, 26, 0, 15, 28, 5, 16, 17, 18, 22, 27, 17, 17, 17, 17 }; /* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_int8 yyr1[] = { 0, 24, 25, 25, 26, 26, 26, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 }; /* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 1, 1, 1, 3, 2, 1, 2, 2, 3, 2, 3, 2, 3, 2, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; enum { YYENOMEM = -2 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYNOMEM goto yyexhaustedlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (yyscanner, lex_env, YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Backward compatibility with an undocumented macro. Use YYerror or YYUNDEF. */ #define YYERRCODE YYUNDEF /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Kind, Value, yyscanner, lex_env); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*-----------------------------------. | Print this symbol's value on YYO. | `-----------------------------------*/ static void yy_symbol_value_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, void *yyscanner, RE_LEX_ENVIRONMENT *lex_env) { FILE *yyoutput = yyo; YY_USE (yyoutput); YY_USE (yyscanner); YY_USE (lex_env); if (!yyvaluep) return; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } /*---------------------------. | Print this symbol on YYO. | `---------------------------*/ static void yy_symbol_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, void *yyscanner, RE_LEX_ENVIRONMENT *lex_env) { YYFPRINTF (yyo, "%s %s (", yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); yy_symbol_value_print (yyo, yykind, yyvaluep, yyscanner, lex_env); YYFPRINTF (yyo, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, int yyrule, void *yyscanner, RE_LEX_ENVIRONMENT *lex_env) { int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), &yyvsp[(yyi + 1) - (yynrhs)], yyscanner, lex_env); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, Rule, yyscanner, lex_env); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) ((void) 0) # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, yysymbol_kind_t yykind, YYSTYPE *yyvaluep, void *yyscanner, RE_LEX_ENVIRONMENT *lex_env) { YY_USE (yyvaluep); YY_USE (yyscanner); YY_USE (lex_env); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN switch (yykind) { case YYSYMBOL__CLASS_: /* _CLASS_ */ #line 98 "re_grammar.y" { yr_free(((*yyvaluep).re_class)); ((*yyvaluep).re_class) = NULL; } #line 966 "re_grammar.c" break; case YYSYMBOL_alternative: /* alternative */ #line 99 "re_grammar.y" { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } #line 972 "re_grammar.c" break; case YYSYMBOL_concatenation: /* concatenation */ #line 100 "re_grammar.y" { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } #line 978 "re_grammar.c" break; case YYSYMBOL_repeat: /* repeat */ #line 101 "re_grammar.y" { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } #line 984 "re_grammar.c" break; case YYSYMBOL_single: /* single */ #line 102 "re_grammar.y" { yr_re_node_destroy(((*yyvaluep).re_node)); ((*yyvaluep).re_node) = NULL; } #line 990 "re_grammar.c" break; default: break; } YY_IGNORE_MAYBE_UNINITIALIZED_END } /*----------. | yyparse. | `----------*/ int yyparse (void *yyscanner, RE_LEX_ENVIRONMENT *lex_env) { /* Lookahead token kind. */ int yychar; /* The semantic value of the lookahead symbol. */ /* Default value used for initialization, for pacifying older GCCs or non-GCC compilers. */ YY_INITIAL_VALUE (static YYSTYPE yyval_default;) YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); /* Number of syntax errors so far. */ int yynerrs = 0; yy_state_fast_t yystate = 0; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus = 0; /* Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* Their size. */ YYPTRDIFF_T yystacksize = YYINITDEPTH; /* The state stack: array, bottom, top. */ yy_state_t yyssa[YYINITDEPTH]; yy_state_t *yyss = yyssa; yy_state_t *yyssp = yyss; /* The semantic value stack: array, bottom, top. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs = yyvsa; YYSTYPE *yyvsp = yyvs; int yyn; /* The return value of yyparse. */ int yyresult; /* Lookahead symbol kind. */ yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; YYDPRINTF ((stderr, "Starting parse\n")); yychar = YYEMPTY; /* Cause a token to be read. */ goto yysetstate; /*------------------------------------------------------------. | yynewstate -- push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; /*--------------------------------------------------------------------. | yysetstate -- set current state (the top of the stack) to yystate. | `--------------------------------------------------------------------*/ yysetstate: YYDPRINTF ((stderr, "Entering state %d\n", yystate)); YY_ASSERT (0 <= yystate && yystate < YYNSTATES); YY_IGNORE_USELESS_CAST_BEGIN *yyssp = YY_CAST (yy_state_t, yystate); YY_IGNORE_USELESS_CAST_END YY_STACK_PRINT (yyss, yyssp); if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE YYNOMEM; #else { /* Get the current used size of the three stacks, in elements. */ YYPTRDIFF_T yysize = yyssp - yyss + 1; # if defined yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ yy_state_t *yyss1 = yyss; YYSTYPE *yyvs1 = yyvs; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * YYSIZEOF (*yyssp), &yyvs1, yysize * YYSIZEOF (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } # else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) YYNOMEM; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yy_state_t *yyss1 = yyss; union yyalloc *yyptr = YY_CAST (union yyalloc *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) YYNOMEM; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YY_IGNORE_USELESS_CAST_BEGIN YYDPRINTF ((stderr, "Stack size increased to %ld\n", YY_CAST (long, yystacksize))); YY_IGNORE_USELESS_CAST_END if (yyss + yystacksize - 1 <= yyssp) YYABORT; } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token\n")); yychar = yylex (&yylval, yyscanner, lex_env); } if (yychar <= YYEOF) { yychar = YYEOF; yytoken = YYSYMBOL_YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else if (yychar == YYerror) { /* The scanner already issued an error message, process directly to error recovery. But do not keep the error token as lookahead, it is too special and may lead us to an endless loop in error recovery. */ yychar = YYUNDEF; yytoken = YYSYMBOL_YYerror; goto yyerrlab1; } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Discard the shifted token. */ yychar = YYEMPTY; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 2: /* re: alternative */ #line 107 "re_grammar.y" { RE_AST* re_ast = yyget_extra(yyscanner); re_ast->root_node = (yyvsp[0].re_node); } #line 1269 "re_grammar.c" break; case 4: /* alternative: concatenation */ #line 116 "re_grammar.y" { (yyval.re_node) = (yyvsp[0].re_node); } #line 1277 "re_grammar.c" break; case 5: /* alternative: alternative '|' concatenation */ #line 120 "re_grammar.y" { mark_as_not_fast_regexp(); (yyval.re_node) = yr_re_node_create(RE_NODE_ALT); destroy_node_if((yyval.re_node) == NULL, (yyvsp[-2].re_node)); destroy_node_if((yyval.re_node) == NULL, (yyvsp[0].re_node)); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child((yyval.re_node), (yyvsp[-2].re_node)); yr_re_node_append_child((yyval.re_node), (yyvsp[0].re_node)); } #line 1295 "re_grammar.c" break; case 6: /* alternative: alternative '|' */ #line 134 "re_grammar.y" { RE_NODE* node; mark_as_not_fast_regexp(); node = yr_re_node_create(RE_NODE_EMPTY); destroy_node_if(node == NULL, (yyvsp[-1].re_node)); fail_if(node == NULL, ERROR_INSUFFICIENT_MEMORY); (yyval.re_node) = yr_re_node_create(RE_NODE_ALT); destroy_node_if((yyval.re_node) == NULL, node); destroy_node_if((yyval.re_node) == NULL, (yyvsp[-1].re_node)); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child((yyval.re_node), (yyvsp[-1].re_node)); yr_re_node_append_child((yyval.re_node), node); } #line 1320 "re_grammar.c" break; case 7: /* concatenation: repeat */ #line 158 "re_grammar.y" { (yyval.re_node) = yr_re_node_create(RE_NODE_CONCAT); destroy_node_if((yyval.re_node) == NULL, (yyvsp[0].re_node)); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child((yyval.re_node), (yyvsp[0].re_node)); } #line 1333 "re_grammar.c" break; case 8: /* concatenation: concatenation repeat */ #line 167 "re_grammar.y" { yr_re_node_append_child((yyvsp[-1].re_node), (yyvsp[0].re_node)); (yyval.re_node) = (yyvsp[-1].re_node); } #line 1342 "re_grammar.c" break; case 9: /* repeat: single '*' */ #line 175 "re_grammar.y" { RE_AST* re_ast; mark_as_not_fast_regexp(); re_ast = yyget_extra(yyscanner); re_ast->flags |= RE_FLAGS_GREEDY; (yyval.re_node) = yr_re_node_create(RE_NODE_STAR); destroy_node_if((yyval.re_node) == NULL, (yyvsp[-1].re_node)); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child((yyval.re_node), (yyvsp[-1].re_node)); } #line 1362 "re_grammar.c" break; case 10: /* repeat: single '*' '?' */ #line 191 "re_grammar.y" { RE_AST* re_ast; mark_as_not_fast_regexp(); re_ast = yyget_extra(yyscanner); re_ast->flags |= RE_FLAGS_UNGREEDY; (yyval.re_node) = yr_re_node_create(RE_NODE_STAR); destroy_node_if((yyval.re_node) == NULL, (yyvsp[-2].re_node)); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child((yyval.re_node), (yyvsp[-2].re_node)); (yyval.re_node)->greedy = false; } #line 1384 "re_grammar.c" break; case 11: /* repeat: single '+' */ #line 209 "re_grammar.y" { RE_AST* re_ast; mark_as_not_fast_regexp(); re_ast = yyget_extra(yyscanner); re_ast->flags |= RE_FLAGS_GREEDY; (yyval.re_node) = yr_re_node_create(RE_NODE_PLUS); destroy_node_if((yyval.re_node) == NULL, (yyvsp[-1].re_node)); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child((yyval.re_node), (yyvsp[-1].re_node)); } #line 1404 "re_grammar.c" break; case 12: /* repeat: single '+' '?' */ #line 225 "re_grammar.y" { RE_AST* re_ast; mark_as_not_fast_regexp(); re_ast = yyget_extra(yyscanner); re_ast->flags |= RE_FLAGS_UNGREEDY; (yyval.re_node) = yr_re_node_create(RE_NODE_PLUS); destroy_node_if((yyval.re_node) == NULL, (yyvsp[-2].re_node)); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child((yyval.re_node), (yyvsp[-2].re_node)); (yyval.re_node)->greedy = false; } #line 1425 "re_grammar.c" break; case 13: /* repeat: single '?' */ #line 242 "re_grammar.y" { RE_AST* re_ast = yyget_extra(yyscanner); re_ast->flags |= RE_FLAGS_GREEDY; if ((yyvsp[-1].re_node)->type == RE_NODE_ANY) { (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE_ANY); destroy_node_if(true, (yyvsp[-1].re_node)); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); } else { mark_as_not_fast_regexp(); (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE); destroy_node_if((yyval.re_node) == NULL, (yyvsp[-1].re_node)); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child((yyval.re_node), (yyvsp[-1].re_node)); } (yyval.re_node)->start = 0; (yyval.re_node)->end = 1; } #line 1452 "re_grammar.c" break; case 14: /* repeat: single '?' '?' */ #line 265 "re_grammar.y" { RE_AST* re_ast = yyget_extra(yyscanner); re_ast->flags |= RE_FLAGS_UNGREEDY; if ((yyvsp[-2].re_node)->type == RE_NODE_ANY) { (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE_ANY); destroy_node_if(true, (yyvsp[-2].re_node)); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); } else { mark_as_not_fast_regexp(); (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE); destroy_node_if((yyval.re_node) == NULL, (yyvsp[-2].re_node)); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child((yyval.re_node), (yyvsp[-2].re_node)); } (yyval.re_node)->start = 0; (yyval.re_node)->end = 1; (yyval.re_node)->greedy = false; } #line 1480 "re_grammar.c" break; case 15: /* repeat: single _RANGE_ */ #line 289 "re_grammar.y" { RE_AST* re_ast = yyget_extra(yyscanner); re_ast->flags |= RE_FLAGS_GREEDY; if ((yyvsp[-1].re_node)->type == RE_NODE_ANY) { (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE_ANY); destroy_node_if(true, (yyvsp[-1].re_node)); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); } else { mark_as_not_fast_regexp(); (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE); destroy_node_if((yyval.re_node) == NULL, (yyvsp[-1].re_node)); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child((yyval.re_node), (yyvsp[-1].re_node)); } (yyval.re_node)->start = (yyvsp[0].range) & 0xFFFF;; (yyval.re_node)->end = (yyvsp[0].range) >> 16;; } #line 1507 "re_grammar.c" break; case 16: /* repeat: single _RANGE_ '?' */ #line 312 "re_grammar.y" { RE_AST* re_ast = yyget_extra(yyscanner); re_ast->flags |= RE_FLAGS_UNGREEDY; if ((yyvsp[-2].re_node)->type == RE_NODE_ANY) { (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE_ANY); destroy_node_if(true, (yyvsp[-2].re_node)); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); } else { mark_as_not_fast_regexp(); (yyval.re_node) = yr_re_node_create(RE_NODE_RANGE); destroy_node_if((yyval.re_node) == NULL, (yyvsp[-2].re_node)); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child((yyval.re_node), (yyvsp[-2].re_node)); } (yyval.re_node)->start = (yyvsp[-1].range) & 0xFFFF;; (yyval.re_node)->end = (yyvsp[-1].range) >> 16;; (yyval.re_node)->greedy = false; } #line 1535 "re_grammar.c" break; case 17: /* repeat: single */ #line 336 "re_grammar.y" { (yyval.re_node) = (yyvsp[0].re_node); } #line 1543 "re_grammar.c" break; case 18: /* repeat: _WORD_BOUNDARY_ */ #line 340 "re_grammar.y" { (yyval.re_node) = yr_re_node_create(RE_NODE_WORD_BOUNDARY); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); } #line 1553 "re_grammar.c" break; case 19: /* repeat: _NON_WORD_BOUNDARY_ */ #line 346 "re_grammar.y" { (yyval.re_node) = yr_re_node_create(RE_NODE_NON_WORD_BOUNDARY); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); } #line 1563 "re_grammar.c" break; case 20: /* repeat: '^' */ #line 352 "re_grammar.y" { (yyval.re_node) = yr_re_node_create(RE_NODE_ANCHOR_START); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); } #line 1573 "re_grammar.c" break; case 21: /* repeat: '$' */ #line 358 "re_grammar.y" { (yyval.re_node) = yr_re_node_create(RE_NODE_ANCHOR_END); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); } #line 1583 "re_grammar.c" break; case 22: /* single: '(' alternative ')' */ #line 367 "re_grammar.y" { (yyval.re_node) = (yyvsp[-1].re_node); } #line 1591 "re_grammar.c" break; case 23: /* single: '.' */ #line 371 "re_grammar.y" { (yyval.re_node) = yr_re_node_create(RE_NODE_ANY); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); (yyval.re_node)->value = 0x00; (yyval.re_node)->mask = 0x00; } #line 1604 "re_grammar.c" break; case 24: /* single: _CHAR_ */ #line 380 "re_grammar.y" { (yyval.re_node) = yr_re_node_create(RE_NODE_LITERAL); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); (yyval.re_node)->value = (yyvsp[0].integer); (yyval.re_node)->mask = 0xFF; } #line 1617 "re_grammar.c" break; case 25: /* single: _WORD_CHAR_ */ #line 389 "re_grammar.y" { (yyval.re_node) = yr_re_node_create(RE_NODE_WORD_CHAR); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); } #line 1627 "re_grammar.c" break; case 26: /* single: _NON_WORD_CHAR_ */ #line 395 "re_grammar.y" { (yyval.re_node) = yr_re_node_create(RE_NODE_NON_WORD_CHAR); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); } #line 1637 "re_grammar.c" break; case 27: /* single: _SPACE_ */ #line 401 "re_grammar.y" { (yyval.re_node) = yr_re_node_create(RE_NODE_SPACE); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); } #line 1647 "re_grammar.c" break; case 28: /* single: _NON_SPACE_ */ #line 407 "re_grammar.y" { (yyval.re_node) = yr_re_node_create(RE_NODE_NON_SPACE); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); } #line 1657 "re_grammar.c" break; case 29: /* single: _DIGIT_ */ #line 413 "re_grammar.y" { (yyval.re_node) = yr_re_node_create(RE_NODE_DIGIT); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); } #line 1667 "re_grammar.c" break; case 30: /* single: _NON_DIGIT_ */ #line 419 "re_grammar.y" { (yyval.re_node) = yr_re_node_create(RE_NODE_NON_DIGIT); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); } #line 1677 "re_grammar.c" break; case 31: /* single: _CLASS_ */ #line 425 "re_grammar.y" { (yyval.re_node) = yr_re_node_create(RE_NODE_CLASS); fail_if((yyval.re_node) == NULL, ERROR_INSUFFICIENT_MEMORY); (yyval.re_node)->re_class = (yyvsp[0].re_class); } #line 1689 "re_grammar.c" break; #line 1693 "re_grammar.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; *++yyvsp = yyval; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ { const int yylhs = yyr1[yyn] - YYNTOKENS; const int yyi = yypgoto[yylhs] + *yyssp; yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp ? yytable[yyi] : yydefgoto[yylhs]); } goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; yyerror (yyscanner, lex_env, YY_("syntax error")); } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval, yyscanner, lex_env); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (0) YYERROR; ++yynerrs; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ /* Pop stack until we find a state that shifts the error token. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYSYMBOL_YYerror; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", YY_ACCESSING_SYMBOL (yystate), yyvsp, yyscanner, lex_env); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturnlab; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturnlab; /*-----------------------------------------------------------. | yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | `-----------------------------------------------------------*/ yyexhaustedlab: yyerror (yyscanner, lex_env, YY_("memory exhausted")); yyresult = 2; goto yyreturnlab; /*----------------------------------------------------------. | yyreturnlab -- parsing is finished, clean up and return. | `----------------------------------------------------------*/ yyreturnlab: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval, yyscanner, lex_env); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", YY_ACCESSING_SYMBOL (+*yyssp), yyvsp, yyscanner, lex_env); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif return yyresult; } #line 433 "re_grammar.y" yara-4.5.3/libyara/re_grammar.h000066400000000000000000000071361501365277300164070ustar00rootroot00000000000000/* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison interface for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. 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 . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, especially those whose name start with YY_ or yy_. They are private implementation details that can be changed or removed. */ #ifndef YY_RE_YY_RE_GRAMMAR_H_INCLUDED # define YY_RE_YY_RE_GRAMMAR_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int re_yydebug; #endif /* Token kinds. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { YYEMPTY = -2, YYEOF = 0, /* "end of file" */ YYerror = 256, /* error */ YYUNDEF = 257, /* "invalid token" */ _CHAR_ = 258, /* _CHAR_ */ _ANY_ = 259, /* _ANY_ */ _RANGE_ = 260, /* _RANGE_ */ _CLASS_ = 261, /* _CLASS_ */ _WORD_CHAR_ = 262, /* _WORD_CHAR_ */ _NON_WORD_CHAR_ = 263, /* _NON_WORD_CHAR_ */ _SPACE_ = 264, /* _SPACE_ */ _NON_SPACE_ = 265, /* _NON_SPACE_ */ _DIGIT_ = 266, /* _DIGIT_ */ _NON_DIGIT_ = 267, /* _NON_DIGIT_ */ _WORD_BOUNDARY_ = 268, /* _WORD_BOUNDARY_ */ _NON_WORD_BOUNDARY_ = 269 /* _NON_WORD_BOUNDARY_ */ }; typedef enum yytokentype yytoken_kind_t; #endif /* Token kinds. */ #define YYEMPTY -2 #define YYEOF 0 #define YYerror 256 #define YYUNDEF 257 #define _CHAR_ 258 #define _ANY_ 259 #define _RANGE_ 260 #define _CLASS_ 261 #define _WORD_CHAR_ 262 #define _NON_WORD_CHAR_ 263 #define _SPACE_ 264 #define _NON_SPACE_ 265 #define _DIGIT_ 266 #define _NON_DIGIT_ 267 #define _WORD_BOUNDARY_ 268 #define _NON_WORD_BOUNDARY_ 269 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 75 "re_grammar.y" int integer; uint32_t range; RE_NODE* re_node; RE_CLASS* re_class; #line 102 "re_grammar.h" }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif int re_yyparse (void *yyscanner, RE_LEX_ENVIRONMENT *lex_env); #endif /* !YY_RE_YY_RE_GRAMMAR_H_INCLUDED */ yara-4.5.3/libyara/re_grammar.y000066400000000000000000000246451501365277300164340ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // clang-format off %{ #include #include #include #include #include #include #include #define YYERROR_VERBOSE #define YYMALLOC yr_malloc #define YYFREE yr_free #define mark_as_not_fast_regexp() \ ((RE_AST*) yyget_extra(yyscanner))->flags &= ~RE_FLAGS_FAST_REGEXP #define fail_if(x, error) \ if (x) \ { \ lex_env->last_error = error; \ YYABORT; \ } \ #define destroy_node_if(x, node) \ if (x) \ { \ yr_re_node_destroy(node); \ } \ %} %name-prefix "re_yy" %pure-parser %parse-param {void *yyscanner} %parse-param {RE_LEX_ENVIRONMENT *lex_env} %lex-param {yyscan_t yyscanner} %lex-param {RE_LEX_ENVIRONMENT *lex_env} %union { int integer; uint32_t range; RE_NODE* re_node; RE_CLASS* re_class; } %token _CHAR_ _ANY_ %token _RANGE_ %token _CLASS_ %token _WORD_CHAR_ %token _NON_WORD_CHAR_ %token _SPACE_ %token _NON_SPACE_ %token _DIGIT_ %token _NON_DIGIT_ %token _WORD_BOUNDARY_ %token _NON_WORD_BOUNDARY_ %type alternative concatenation repeat single %destructor { yr_free($$); $$ = NULL; } _CLASS_ %destructor { yr_re_node_destroy($$); $$ = NULL; } alternative %destructor { yr_re_node_destroy($$); $$ = NULL; } concatenation %destructor { yr_re_node_destroy($$); $$ = NULL; } repeat %destructor { yr_re_node_destroy($$); $$ = NULL; } single %% re : alternative { RE_AST* re_ast = yyget_extra(yyscanner); re_ast->root_node = $1; } | error ; alternative : concatenation { $$ = $1; } | alternative '|' concatenation { mark_as_not_fast_regexp(); $$ = yr_re_node_create(RE_NODE_ALT); destroy_node_if($$ == NULL, $1); destroy_node_if($$ == NULL, $3); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child($$, $1); yr_re_node_append_child($$, $3); } | alternative '|' { RE_NODE* node; mark_as_not_fast_regexp(); node = yr_re_node_create(RE_NODE_EMPTY); destroy_node_if(node == NULL, $1); fail_if(node == NULL, ERROR_INSUFFICIENT_MEMORY); $$ = yr_re_node_create(RE_NODE_ALT); destroy_node_if($$ == NULL, node); destroy_node_if($$ == NULL, $1); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child($$, $1); yr_re_node_append_child($$, node); } ; concatenation : repeat { $$ = yr_re_node_create(RE_NODE_CONCAT); destroy_node_if($$ == NULL, $1); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child($$, $1); } | concatenation repeat { yr_re_node_append_child($1, $2); $$ = $1; } ; repeat : single '*' { RE_AST* re_ast; mark_as_not_fast_regexp(); re_ast = yyget_extra(yyscanner); re_ast->flags |= RE_FLAGS_GREEDY; $$ = yr_re_node_create(RE_NODE_STAR); destroy_node_if($$ == NULL, $1); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child($$, $1); } | single '*' '?' { RE_AST* re_ast; mark_as_not_fast_regexp(); re_ast = yyget_extra(yyscanner); re_ast->flags |= RE_FLAGS_UNGREEDY; $$ = yr_re_node_create(RE_NODE_STAR); destroy_node_if($$ == NULL, $1); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child($$, $1); $$->greedy = false; } | single '+' { RE_AST* re_ast; mark_as_not_fast_regexp(); re_ast = yyget_extra(yyscanner); re_ast->flags |= RE_FLAGS_GREEDY; $$ = yr_re_node_create(RE_NODE_PLUS); destroy_node_if($$ == NULL, $1); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child($$, $1); } | single '+' '?' { RE_AST* re_ast; mark_as_not_fast_regexp(); re_ast = yyget_extra(yyscanner); re_ast->flags |= RE_FLAGS_UNGREEDY; $$ = yr_re_node_create(RE_NODE_PLUS); destroy_node_if($$ == NULL, $1); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child($$, $1); $$->greedy = false; } | single '?' { RE_AST* re_ast = yyget_extra(yyscanner); re_ast->flags |= RE_FLAGS_GREEDY; if ($1->type == RE_NODE_ANY) { $$ = yr_re_node_create(RE_NODE_RANGE_ANY); destroy_node_if(true, $1); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); } else { mark_as_not_fast_regexp(); $$ = yr_re_node_create(RE_NODE_RANGE); destroy_node_if($$ == NULL, $1); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child($$, $1); } $$->start = 0; $$->end = 1; } | single '?' '?' { RE_AST* re_ast = yyget_extra(yyscanner); re_ast->flags |= RE_FLAGS_UNGREEDY; if ($1->type == RE_NODE_ANY) { $$ = yr_re_node_create(RE_NODE_RANGE_ANY); destroy_node_if(true, $1); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); } else { mark_as_not_fast_regexp(); $$ = yr_re_node_create(RE_NODE_RANGE); destroy_node_if($$ == NULL, $1); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child($$, $1); } $$->start = 0; $$->end = 1; $$->greedy = false; } | single _RANGE_ { RE_AST* re_ast = yyget_extra(yyscanner); re_ast->flags |= RE_FLAGS_GREEDY; if ($1->type == RE_NODE_ANY) { $$ = yr_re_node_create(RE_NODE_RANGE_ANY); destroy_node_if(true, $1); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); } else { mark_as_not_fast_regexp(); $$ = yr_re_node_create(RE_NODE_RANGE); destroy_node_if($$ == NULL, $1); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child($$, $1); } $$->start = $2 & 0xFFFF;; $$->end = $2 >> 16;; } | single _RANGE_ '?' { RE_AST* re_ast = yyget_extra(yyscanner); re_ast->flags |= RE_FLAGS_UNGREEDY; if ($1->type == RE_NODE_ANY) { $$ = yr_re_node_create(RE_NODE_RANGE_ANY); destroy_node_if(true, $1); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); } else { mark_as_not_fast_regexp(); $$ = yr_re_node_create(RE_NODE_RANGE); destroy_node_if($$ == NULL, $1); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); yr_re_node_append_child($$, $1); } $$->start = $2 & 0xFFFF;; $$->end = $2 >> 16;; $$->greedy = false; } | single { $$ = $1; } | _WORD_BOUNDARY_ { $$ = yr_re_node_create(RE_NODE_WORD_BOUNDARY); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); } | _NON_WORD_BOUNDARY_ { $$ = yr_re_node_create(RE_NODE_NON_WORD_BOUNDARY); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); } | '^' { $$ = yr_re_node_create(RE_NODE_ANCHOR_START); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); } | '$' { $$ = yr_re_node_create(RE_NODE_ANCHOR_END); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); } ; single : '(' alternative ')' { $$ = $2; } | '.' { $$ = yr_re_node_create(RE_NODE_ANY); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); $$->value = 0x00; $$->mask = 0x00; } | _CHAR_ { $$ = yr_re_node_create(RE_NODE_LITERAL); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); $$->value = $1; $$->mask = 0xFF; } | _WORD_CHAR_ { $$ = yr_re_node_create(RE_NODE_WORD_CHAR); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); } | _NON_WORD_CHAR_ { $$ = yr_re_node_create(RE_NODE_NON_WORD_CHAR); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); } | _SPACE_ { $$ = yr_re_node_create(RE_NODE_SPACE); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); } | _NON_SPACE_ { $$ = yr_re_node_create(RE_NODE_NON_SPACE); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); } | _DIGIT_ { $$ = yr_re_node_create(RE_NODE_DIGIT); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); } | _NON_DIGIT_ { $$ = yr_re_node_create(RE_NODE_NON_DIGIT); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); } | _CLASS_ { $$ = yr_re_node_create(RE_NODE_CLASS); fail_if($$ == NULL, ERROR_INSUFFICIENT_MEMORY); $$->re_class = $1; } ; %% yara-4.5.3/libyara/re_lexer.c000066400000000000000000002275261501365277300161020ustar00rootroot00000000000000#line 1 "libyara/re_lexer.c" #line 3 "libyara/re_lexer.c" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 6 #define YY_FLEX_SUBMINOR_VERSION 4 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif #ifdef yy_create_buffer #define re_yy_create_buffer_ALREADY_DEFINED #else #define yy_create_buffer re_yy_create_buffer #endif #ifdef yy_delete_buffer #define re_yy_delete_buffer_ALREADY_DEFINED #else #define yy_delete_buffer re_yy_delete_buffer #endif #ifdef yy_scan_buffer #define re_yy_scan_buffer_ALREADY_DEFINED #else #define yy_scan_buffer re_yy_scan_buffer #endif #ifdef yy_scan_string #define re_yy_scan_string_ALREADY_DEFINED #else #define yy_scan_string re_yy_scan_string #endif #ifdef yy_scan_bytes #define re_yy_scan_bytes_ALREADY_DEFINED #else #define yy_scan_bytes re_yy_scan_bytes #endif #ifdef yy_init_buffer #define re_yy_init_buffer_ALREADY_DEFINED #else #define yy_init_buffer re_yy_init_buffer #endif #ifdef yy_flush_buffer #define re_yy_flush_buffer_ALREADY_DEFINED #else #define yy_flush_buffer re_yy_flush_buffer #endif #ifdef yy_load_buffer_state #define re_yy_load_buffer_state_ALREADY_DEFINED #else #define yy_load_buffer_state re_yy_load_buffer_state #endif #ifdef yy_switch_to_buffer #define re_yy_switch_to_buffer_ALREADY_DEFINED #else #define yy_switch_to_buffer re_yy_switch_to_buffer #endif #ifdef yypush_buffer_state #define re_yypush_buffer_state_ALREADY_DEFINED #else #define yypush_buffer_state re_yypush_buffer_state #endif #ifdef yypop_buffer_state #define re_yypop_buffer_state_ALREADY_DEFINED #else #define yypop_buffer_state re_yypop_buffer_state #endif #ifdef yyensure_buffer_stack #define re_yyensure_buffer_stack_ALREADY_DEFINED #else #define yyensure_buffer_stack re_yyensure_buffer_stack #endif #ifdef yylex #define re_yylex_ALREADY_DEFINED #else #define yylex re_yylex #endif #ifdef yyrestart #define re_yyrestart_ALREADY_DEFINED #else #define yyrestart re_yyrestart #endif #ifdef yylex_init #define re_yylex_init_ALREADY_DEFINED #else #define yylex_init re_yylex_init #endif #ifdef yylex_init_extra #define re_yylex_init_extra_ALREADY_DEFINED #else #define yylex_init_extra re_yylex_init_extra #endif #ifdef yylex_destroy #define re_yylex_destroy_ALREADY_DEFINED #else #define yylex_destroy re_yylex_destroy #endif #ifdef yyget_debug #define re_yyget_debug_ALREADY_DEFINED #else #define yyget_debug re_yyget_debug #endif #ifdef yyset_debug #define re_yyset_debug_ALREADY_DEFINED #else #define yyset_debug re_yyset_debug #endif #ifdef yyget_extra #define re_yyget_extra_ALREADY_DEFINED #else #define yyget_extra re_yyget_extra #endif #ifdef yyset_extra #define re_yyset_extra_ALREADY_DEFINED #else #define yyset_extra re_yyset_extra #endif #ifdef yyget_in #define re_yyget_in_ALREADY_DEFINED #else #define yyget_in re_yyget_in #endif #ifdef yyset_in #define re_yyset_in_ALREADY_DEFINED #else #define yyset_in re_yyset_in #endif #ifdef yyget_out #define re_yyget_out_ALREADY_DEFINED #else #define yyget_out re_yyget_out #endif #ifdef yyset_out #define re_yyset_out_ALREADY_DEFINED #else #define yyset_out re_yyset_out #endif #ifdef yyget_leng #define re_yyget_leng_ALREADY_DEFINED #else #define yyget_leng re_yyget_leng #endif #ifdef yyget_text #define re_yyget_text_ALREADY_DEFINED #else #define yyget_text re_yyget_text #endif #ifdef yyget_lineno #define re_yyget_lineno_ALREADY_DEFINED #else #define yyget_lineno re_yyget_lineno #endif #ifdef yyset_lineno #define re_yyset_lineno_ALREADY_DEFINED #else #define yyset_lineno re_yyset_lineno #endif #ifdef yyget_column #define re_yyget_column_ALREADY_DEFINED #else #define yyget_column re_yyget_column #endif #ifdef yyset_column #define re_yyset_column_ALREADY_DEFINED #else #define yyset_column re_yyset_column #endif #ifdef yywrap #define re_yywrap_ALREADY_DEFINED #else #define yywrap re_yywrap #endif #ifdef yyget_lval #define re_yyget_lval_ALREADY_DEFINED #else #define yyget_lval re_yyget_lval #endif #ifdef yyset_lval #define re_yyset_lval_ALREADY_DEFINED #else #define yyset_lval re_yyset_lval #endif #ifdef yyalloc #define re_yyalloc_ALREADY_DEFINED #else #define yyalloc re_yyalloc #endif #ifdef yyrealloc #define re_yyrealloc_ALREADY_DEFINED #else #define yyrealloc re_yyrealloc #endif #ifdef yyfree #define re_yyfree_ALREADY_DEFINED #else #define yyfree re_yyfree #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #ifndef SIZE_MAX #define SIZE_MAX (~(size_t)0) #endif #endif /* ! C99 */ #endif /* ! FLEXINT_H */ /* begin standard C++ headers. */ /* TODO: this is always defined, so inline it */ #define yyconst const #if defined(__GNUC__) && __GNUC__ >= 3 #define yynoreturn __attribute__((__noreturn__)) #else #define yynoreturn #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an * integer in range [0..255] for use as an array index. */ #define YY_SC_TO_UI(c) ((YY_CHAR) (c)) /* An opaque pointer. */ #ifndef YY_TYPEDEF_YY_SCANNER_T #define YY_TYPEDEF_YY_SCANNER_T typedef void* yyscan_t; #endif /* For convenience, these vars (plus the bison vars far below) are macros in the reentrant scanner. */ #define yyin yyg->yyin_r #define yyout yyg->yyout_r #define yyextra yyg->yyextra_r #define yyleng yyg->yyleng_r #define yytext yyg->yytext_r #define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) #define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) #define yy_flex_debug yyg->yy_flex_debug_r /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN yyg->yy_start = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START ((yyg->yy_start - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart( yyin , yyscanner ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k. * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. * Ditto for the __ia64__ case accordingly. */ #define YY_BUF_SIZE 32768 #else #define YY_BUF_SIZE 16384 #endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires * access to the local variable yy_act. Since yyless() is a macro, it would break * existing scanners that call yyless() from OUTSIDE yylex. * One obvious solution it to make yy_act a global. I tried that, and saw * a 5% performance hit in a non-yylineno scanner, because yy_act is * normally declared as a register variable-- so it is not worth it. */ #define YY_LESS_LINENO(n) \ do { \ int yyl;\ for ( yyl = n; yyl < yyleng; ++yyl )\ if ( yytext[yyl] == '\n' )\ --yylineno;\ }while(0) #define YY_LINENO_REWIND_TO(dst) \ do {\ const char *p;\ for ( p = yy_cp-1; p >= (dst); --p)\ if ( *p == '\n' )\ --yylineno;\ }while(0) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = yyg->yy_hold_char; \ YY_RESTORE_YY_MORE_OFFSET \ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ int yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] void yyrestart ( FILE *input_file , yyscan_t yyscanner ); void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); void yypop_buffer_state ( yyscan_t yyscanner ); static void yyensure_buffer_stack ( yyscan_t yyscanner ); static void yy_load_buffer_state ( yyscan_t yyscanner ); static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file , yyscan_t yyscanner ); #define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER , yyscanner) YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); void *yyalloc ( yy_size_t , yyscan_t yyscanner ); void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); void yyfree ( void * , yyscan_t yyscanner ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (yyscanner); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (yyscanner); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ #define re_yywrap(yyscanner) (/*CONSTCOND*/1) #define YY_SKIP_YYWRAP typedef flex_uint8_t YY_CHAR; typedef int yy_state_type; #define yytext_ptr yytext_r static yy_state_type yy_get_previous_state ( yyscan_t yyscanner ); static yy_state_type yy_try_NUL_trans ( yy_state_type current_state , yyscan_t yyscanner); static int yy_get_next_buffer ( yyscan_t yyscanner ); static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ yyg->yytext_ptr = yy_bp; \ yyleng = (int) (yy_cp - yy_bp); \ yyg->yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; #define YY_NUM_RULES 29 #define YY_END_OF_BUFFER 30 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static const flex_int16_t yy_accept[47] = { 0, 0, 0, 0, 0, 30, 7, 7, 28, 6, 17, 7, 27, 29, 26, 18, 5, 3, 16, 15, 13, 11, 9, 14, 12, 10, 8, 0, 0, 0, 0, 0, 25, 23, 21, 24, 22, 20, 0, 4, 0, 0, 1, 2, 19, 0, 0 } ; static const YY_CHAR yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 4, 1, 1, 1, 4, 4, 4, 4, 5, 6, 4, 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 4, 1, 8, 9, 8, 10, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 11, 1, 1, 1, 12, 1, 1, 1, 13, 14, 15, 16, 1, 1, 8, 17, 8, 18, 8, 8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 19, 1, 1, 1, 20, 21, 1, 1, 22, 4, 23, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static const YY_CHAR yy_meta[24] = { 0, 1, 2, 1, 1, 1, 3, 4, 4, 4, 4, 1, 1, 1, 1, 5, 1, 4, 4, 1, 1, 1, 1, 1 } ; static const flex_int16_t yy_base[53] = { 0, 0, 21, 3, 5, 53, 112, 112, 112, 11, 37, 3, 45, 44, 48, 112, 112, 27, 33, 112, 112, 112, 112, 112, 112, 112, 112, 6, 29, 67, 0, 33, 32, 27, 25, 24, 23, 18, 15, 112, 38, 5, 112, 112, 112, 0, 112, 90, 95, 100, 105, 107, 11 } ; static const flex_int16_t yy_def[53] = { 0, 47, 47, 48, 48, 46, 46, 46, 46, 46, 46, 46, 46, 46, 49, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 50, 46, 46, 46, 46, 46, 46, 46, 51, 46, 46, 46, 46, 46, 46, 52, 0, 46, 46, 46, 46, 46, 46 } ; static const flex_int16_t yy_nxt[136] = { 0, 46, 7, 46, 8, 13, 27, 13, 28, 27, 29, 28, 41, 9, 10, 31, 8, 14, 15, 14, 15, 30, 11, 7, 30, 8, 16, 17, 42, 30, 30, 30, 40, 30, 9, 10, 41, 8, 30, 30, 18, 40, 39, 11, 18, 41, 19, 20, 21, 22, 30, 30, 42, 46, 23, 24, 25, 26, 32, 33, 34, 42, 46, 46, 46, 46, 35, 36, 37, 38, 27, 46, 28, 46, 29, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 43, 6, 6, 6, 6, 6, 12, 12, 12, 12, 12, 31, 46, 31, 31, 31, 44, 44, 44, 44, 45, 45, 5, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46 } ; static const flex_int16_t yy_chk[136] = { 0, 0, 1, 0, 1, 3, 11, 4, 11, 27, 11, 27, 41, 1, 1, 52, 1, 3, 3, 4, 4, 38, 1, 2, 37, 2, 9, 9, 41, 36, 35, 34, 28, 33, 2, 2, 28, 2, 32, 31, 18, 40, 17, 2, 10, 40, 10, 10, 10, 10, 13, 12, 28, 5, 10, 10, 10, 10, 14, 14, 14, 40, 0, 0, 0, 0, 14, 14, 14, 14, 29, 0, 29, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 47, 47, 47, 47, 47, 48, 48, 48, 48, 48, 49, 0, 49, 49, 49, 50, 50, 50, 50, 51, 51, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46 } ; /* Table of booleans, true if rule could match eol. */ static const flex_int32_t yy_rule_can_match_eol[30] = { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET #line 1 "libyara/re_lexer.l" /* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Lexical analyzer for regular expressions */ #line 33 "libyara/re_lexer.l" /* Disable warnings for unused functions in this file. As we redefine YY_FATAL_ERROR macro to use our own function re_yyfatal, the yy_fatal_error function generated by Flex is not actually used, causing a compiler warning. Flex doesn't offer any options to remove the yy_fatal_error function. When they include something like %option noyy_fatal_error as they do with noyywrap then we can remove this pragma. */ #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wunused-function" #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #define snprintf _snprintf #endif // Bitmap with 1 bit for each of the 256 characters in the ASCII table. The bit // is set to 1 if the corresponding character is alphanumeric or 0 if otherwise. static uint8_t word_chars[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 0xFE, 0xFF, 0xFF, 0x87, 0xFE, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // Bitmap with 1 bit for each of the 256 characters in the ASCII table. The bit // is set to 1 if the corresponding character is considered a space. Space // characters include horizontal and vertical tabs, carriage return, new line // and form feed (\t, \v, \r, \n, \f). static uint8_t space_chars[] = { 0x00, 0x3E, 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 }; int escaped_char_value( char* text, uint8_t* value, bool strict_escape); int read_escaped_char( yyscan_t yyscanner, uint8_t* escaped_char, bool strict_escape); #line 803 "libyara/re_lexer.c" #define YY_NO_UNISTD_H 1 #line 806 "libyara/re_lexer.c" #define INITIAL 0 #define char_class 1 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif /* Holds the entire state of the reentrant scanner. */ struct yyguts_t { /* User-defined. Not touched by flex. */ YY_EXTRA_TYPE yyextra_r; /* The rest are the same as the globals declared in the non-reentrant scanner. */ FILE *yyin_r, *yyout_r; size_t yy_buffer_stack_top; /**< index of top of stack. */ size_t yy_buffer_stack_max; /**< capacity of stack. */ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ char yy_hold_char; int yy_n_chars; int yyleng_r; char *yy_c_buf_p; int yy_init; int yy_start; int yy_did_buffer_switch_on_eof; int yy_start_stack_ptr; int yy_start_stack_depth; int *yy_start_stack; yy_state_type yy_last_accepting_state; char* yy_last_accepting_cpos; int yylineno_r; int yy_flex_debug_r; char *yytext_r; int yy_more_flag; int yy_more_len; YYSTYPE * yylval_r; }; /* end struct yyguts_t */ static int yy_init_globals ( yyscan_t yyscanner ); /* This must go here because YYSTYPE and YYLTYPE are included * from bison output in section 1.*/ # define yylval yyg->yylval_r int yylex_init (yyscan_t* scanner); int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int yylex_destroy ( yyscan_t yyscanner ); int yyget_debug ( yyscan_t yyscanner ); void yyset_debug ( int debug_flag , yyscan_t yyscanner ); YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); FILE *yyget_in ( yyscan_t yyscanner ); void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); FILE *yyget_out ( yyscan_t yyscanner ); void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); int yyget_leng ( yyscan_t yyscanner ); char *yyget_text ( yyscan_t yyscanner ); int yyget_lineno ( yyscan_t yyscanner ); void yyset_lineno ( int _line_number , yyscan_t yyscanner ); int yyget_column ( yyscan_t yyscanner ); void yyset_column ( int _column_no , yyscan_t yyscanner ); YYSTYPE * yyget_lval ( yyscan_t yyscanner ); void yyset_lval ( YYSTYPE * yylval_param , yyscan_t yyscanner ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap ( yyscan_t yyscanner ); #else extern int yywrap ( yyscan_t yyscanner ); #endif #endif #ifndef YY_NO_UNPUT #endif #ifndef yytext_ptr static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen ( const char * , yyscan_t yyscanner); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput ( yyscan_t yyscanner ); #else static int input ( yyscan_t yyscanner ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k */ #define YY_READ_BUF_SIZE 16384 #else #define YY_READ_BUF_SIZE 8192 #endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ int n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex \ (YYSTYPE * yylval_param , yyscan_t yyscanner); #define YY_DECL int yylex \ (YYSTYPE * yylval_param , yyscan_t yyscanner) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK /*LINTED*/break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { yy_state_type yy_current_state; char *yy_cp, *yy_bp; int yy_act; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yylval = yylval_param; if ( !yyg->yy_init ) { yyg->yy_init = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! yyg->yy_start ) yyg->yy_start = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (yyscanner); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); } yy_load_buffer_state( yyscanner ); } { #line 114 "libyara/re_lexer.l" #line 1082 "libyara/re_lexer.c" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { yy_cp = yyg->yy_c_buf_p; /* Support of yytext. */ *yy_cp = yyg->yy_hold_char; /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = yyg->yy_start; yy_match: do { YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 47 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } while ( yy_current_state != 46 ); yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; yy_find_action: yy_act = yy_accept[yy_current_state]; YY_DO_BEFORE_ACTION; if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) { int yyl; for ( yyl = 0; yyl < yyleng; ++yyl ) if ( yytext[yyl] == '\n' ) do{ yylineno++; yycolumn=0; }while(0) ; } do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = yyg->yy_hold_char; yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; goto yy_find_action; case 1: YY_RULE_SETUP #line 116 "libyara/re_lexer.l" { // Examples: {3,8} {3, 8}, {3 ,8} {3 , 8} {0,5} {,5} {7,} int hi_bound; int lo_bound = atoi(yytext + 1); char* comma = strchr(yytext, ','); char* hi_bound_ptr = comma + 1; // Skip spaces after the comma, if any. while (*hi_bound_ptr == ' ') hi_bound_ptr++; if (*hi_bound_ptr == '}') hi_bound = RE_MAX_RANGE; else hi_bound = atoi(hi_bound_ptr); if (hi_bound > RE_MAX_RANGE) { yyerror(yyscanner, lex_env, "repeat interval too large"); yyterminate(); } if (hi_bound < lo_bound || hi_bound < 0 || lo_bound < 0) { yyerror(yyscanner, lex_env, "bad repeat interval"); yyterminate(); } yylval->range = (hi_bound << 16) | lo_bound; return _RANGE_; } YY_BREAK case 2: YY_RULE_SETUP #line 152 "libyara/re_lexer.l" { // Example: {10} int value = atoi(yytext + 1); // atoi can return a negative value if the input string represents a number // too large to fit in an integer. if (value > RE_MAX_RANGE || value < 0) { yyerror(yyscanner, lex_env, "repeat interval too large"); yyterminate(); } yylval->range = (value << 16) | value; return _RANGE_; } YY_BREAK case 3: YY_RULE_SETUP #line 173 "libyara/re_lexer.l" { // Start of a negated character class. Example: [^abcd] BEGIN(char_class); memset(LEX_ENV->re_class.bitmap, 0, 32); LEX_ENV->re_class.negated = true; } YY_BREAK case 4: YY_RULE_SETUP #line 182 "libyara/re_lexer.l" { // Start of character negated class containing a ]. // Example: [^]abc] this must be interpreted as a class // not matching ], a, b, nor c BEGIN(char_class); memset(LEX_ENV->re_class.bitmap, 0, 32); LEX_ENV->re_class.negated = true; LEX_ENV->re_class.bitmap[']' / 8] |= 1 << ']' % 8; } YY_BREAK case 5: YY_RULE_SETUP #line 195 "libyara/re_lexer.l" { // Start of character class containing a ]. // Example: []abc] this must be interpreted as a class // matching ], a, b, or c. BEGIN(char_class); memset(LEX_ENV->re_class.bitmap, 0, 32); LEX_ENV->re_class.negated = false; LEX_ENV->re_class.bitmap[']' / 8] |= 1 << ']' % 8; } YY_BREAK case 6: YY_RULE_SETUP #line 208 "libyara/re_lexer.l" { // Start of character class. Example: [abcd] BEGIN(char_class); memset(LEX_ENV->re_class.bitmap, 0, 32); LEX_ENV->re_class.negated = false; } YY_BREAK case 7: /* rule 7 can match eol */ YY_RULE_SETUP #line 218 "libyara/re_lexer.l" { // Any non-special character is passed as a CHAR token to the scanner. yylval->integer = yytext[0]; return _CHAR_; } YY_BREAK case 8: YY_RULE_SETUP #line 227 "libyara/re_lexer.l" { return _WORD_CHAR_; } YY_BREAK case 9: YY_RULE_SETUP #line 232 "libyara/re_lexer.l" { return _NON_WORD_CHAR_; } YY_BREAK case 10: YY_RULE_SETUP #line 237 "libyara/re_lexer.l" { return _SPACE_; } YY_BREAK case 11: YY_RULE_SETUP #line 242 "libyara/re_lexer.l" { return _NON_SPACE_; } YY_BREAK case 12: YY_RULE_SETUP #line 247 "libyara/re_lexer.l" { return _DIGIT_; } YY_BREAK case 13: YY_RULE_SETUP #line 252 "libyara/re_lexer.l" { return _NON_DIGIT_; } YY_BREAK case 14: YY_RULE_SETUP #line 257 "libyara/re_lexer.l" { return _WORD_BOUNDARY_; } YY_BREAK case 15: YY_RULE_SETUP #line 261 "libyara/re_lexer.l" { return _NON_WORD_BOUNDARY_; } YY_BREAK case 16: YY_RULE_SETUP #line 266 "libyara/re_lexer.l" { yyerror(yyscanner, lex_env, "backreferences are not allowed"); yyterminate(); } YY_BREAK case 17: YY_RULE_SETUP #line 273 "libyara/re_lexer.l" { uint8_t c; int return_code; return_code = read_escaped_char(yyscanner, &c, LEX_ENV->strict_escape); if (return_code == VALID_ESCAPE_SEQUENCE) { yylval->integer = c; return _CHAR_; } else if (return_code == UNKNOWN_ESCAPE_SEQUENCE) { yywarning(yyscanner, lex_env, "unknown escape sequence"); yylval->integer = c; return _CHAR_; } else { yyerror(yyscanner, lex_env, "illegal escape sequence"); yyterminate(); } } YY_BREAK case 18: YY_RULE_SETUP #line 298 "libyara/re_lexer.l" { // End of character class. yylval->re_class = (RE_CLASS*) yr_malloc(sizeof(RE_CLASS)); memcpy(yylval->re_class->bitmap, LEX_ENV->re_class.bitmap, 32); yylval->re_class->negated = LEX_ENV->re_class.negated; BEGIN(INITIAL); return _CLASS_; } YY_BREAK case 19: /* rule 19 can match eol */ YY_RULE_SETUP #line 312 "libyara/re_lexer.l" { // A range inside a character class. The regexp is... // // ( \x{hex_digit}{2} Hex digit (i.e: \x01) ... // | \. ...or any escaped character (i.e. \\, \-) ... // | [^]\] ...or any character except ] and \ ... // ) // - ... followed by - // [^]] ... followed by any character except ] // // Some examples: // // [abc0-9] // ^-^ matching range 0-9 // // [a-za-] // ^-^- matching range a-z // // [\.-a] // ^--^- matching range \.-a // uint16_t c; uint8_t start = yytext[0]; uint8_t end = yytext[2]; if (start == '\\') { if (!escaped_char_value(yytext, &start, LEX_ENV->strict_escape)) { yyerror(yyscanner, lex_env, "illegal escape sequence"); yyterminate(); } if (yytext[1] == 'x') end = yytext[5]; else end = yytext[3]; } if (end == '\\') { if (!read_escaped_char(yyscanner, &end, LEX_ENV->strict_escape)) { yyerror(yyscanner, lex_env, "illegal escape sequence"); yyterminate(); } } if (end < start) { yyerror(yyscanner, lex_env, "bad character range"); yyterminate(); } for (c = start; c <= end; c++) { LEX_ENV->re_class.bitmap[c / 8] |= 1 << c % 8; } } YY_BREAK case 20: YY_RULE_SETUP #line 375 "libyara/re_lexer.l" { for (int i = 0; i < 32; i++) LEX_ENV->re_class.bitmap[i] |= word_chars[i]; } YY_BREAK case 21: YY_RULE_SETUP #line 382 "libyara/re_lexer.l" { for (int i = 0; i < 32; i++) LEX_ENV->re_class.bitmap[i] |= ~word_chars[i]; } YY_BREAK case 22: YY_RULE_SETUP #line 389 "libyara/re_lexer.l" { for (int i = 0; i < 32; i++) LEX_ENV->re_class.bitmap[i] |= space_chars[i]; } YY_BREAK case 23: YY_RULE_SETUP #line 396 "libyara/re_lexer.l" { for (int i = 0; i < 32; i++) LEX_ENV->re_class.bitmap[i] |= ~space_chars[i]; } YY_BREAK case 24: YY_RULE_SETUP #line 403 "libyara/re_lexer.l" { for (char c = '0'; c <= '9'; c++) LEX_ENV->re_class.bitmap[c / 8] |= 1 << c % 8; } YY_BREAK case 25: YY_RULE_SETUP #line 410 "libyara/re_lexer.l" { for (int i = 0; i < 32; i++) { // digits 0-7 are in the sixth byte of the vector, let that byte alone if (i == 6) continue; // digits 8 and 9 are the lowest two bits in the seventh byte of the // vector, let those bits alone. if (i == 7) LEX_ENV->re_class.bitmap[i] |= 0xFC; else LEX_ENV->re_class.bitmap[i] = 0xFF; } } YY_BREAK case 26: YY_RULE_SETUP #line 428 "libyara/re_lexer.l" { uint8_t c; int return_code; return_code = read_escaped_char(yyscanner, &c, LEX_ENV->strict_escape); if (return_code == VALID_ESCAPE_SEQUENCE) { LEX_ENV->re_class.bitmap[c / 8] |= 1 << c % 8; } else if (return_code == UNKNOWN_ESCAPE_SEQUENCE) { yywarning(yyscanner, lex_env, "unknown escape sequence"); LEX_ENV->re_class.bitmap[c / 8] |= 1 << c % 8; } else { yyerror(yyscanner, lex_env, "illegal escape sequence"); yyterminate(); } } YY_BREAK case 27: YY_RULE_SETUP #line 451 "libyara/re_lexer.l" { if (yytext[0] >= 32 && yytext[0] < 127) { // A character class (i.e: [0-9a-f]) is represented by a 256-bits vector, // here we set to 1 the vector's bit corresponding to the input character. LEX_ENV->re_class.bitmap[yytext[0] / 8] |= 1 << yytext[0] % 8; } else { yyerror(yyscanner, lex_env, "non-ascii character"); yyterminate(); } } YY_BREAK case YY_STATE_EOF(char_class): #line 468 "libyara/re_lexer.l" { // End of regexp reached while scanning a character class. yyerror(yyscanner, lex_env, "missing terminating ] for character class"); yyterminate(); } YY_BREAK case 28: YY_RULE_SETUP #line 477 "libyara/re_lexer.l" { if (yytext[0] >= 32 && yytext[0] < 127) { return yytext[0]; } else { yyerror(yyscanner, lex_env, "non-ascii character"); yyterminate(); } } YY_BREAK case YY_STATE_EOF(INITIAL): #line 491 "libyara/re_lexer.l" { yyterminate(); } YY_BREAK case 29: YY_RULE_SETUP #line 496 "libyara/re_lexer.l" ECHO; YY_BREAK #line 1594 "libyara/re_lexer.c" case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = yyg->yy_hold_char; YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) { /* This was really a NUL. */ yy_state_type yy_next_state; yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( yyscanner ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++yyg->yy_c_buf_p; yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = yyg->yy_last_accepting_cpos; yy_current_state = yyg->yy_last_accepting_state; goto yy_find_action; } } else switch ( yy_get_next_buffer( yyscanner ) ) { case EOB_ACT_END_OF_FILE: { yyg->yy_did_buffer_switch_on_eof = 0; if ( yywrap( yyscanner ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( yyscanner ); yy_cp = yyg->yy_c_buf_p; yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: yyg->yy_c_buf_p = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; yy_current_state = yy_get_previous_state( yyscanner ); yy_cp = yyg->yy_c_buf_p; yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of user's declarations */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; char *source = yyg->yytext_ptr; int number_to_move, i; int ret_val; if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr - 1); for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; int yy_c_buf_p_offset = (int) (yyg->yy_c_buf_p - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc( (void *) b->yy_ch_buf, (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = NULL; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), yyg->yy_n_chars, num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } if ( yyg->yy_n_chars == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart( yyin , yyscanner); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if ((yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ int new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size , yyscanner ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); /* "- 2" to take care of EOB's */ YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); } yyg->yy_n_chars += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (yyscan_t yyscanner) { yy_state_type yy_current_state; char *yy_cp; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_current_state = yyg->yy_start; for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) { YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 47 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) { int yy_is_jam; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ char *yy_cp = yyg->yy_c_buf_p; YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { yyg->yy_last_accepting_state = yy_current_state; yyg->yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 47 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; yy_is_jam = (yy_current_state == 46); (void)yyg; return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (yyscan_t yyscanner) #else static int input (yyscan_t yyscanner) #endif { int c; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; *yyg->yy_c_buf_p = yyg->yy_hold_char; if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) /* This was really a NUL. */ *yyg->yy_c_buf_p = '\0'; else { /* need more input */ int offset = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr); ++yyg->yy_c_buf_p; switch ( yy_get_next_buffer( yyscanner ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart( yyin , yyscanner); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( yyscanner ) ) return 0; if ( ! yyg->yy_did_buffer_switch_on_eof ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(yyscanner); #else return input(yyscanner); #endif } case EOB_ACT_CONTINUE_SCAN: yyg->yy_c_buf_p = yyg->yytext_ptr + offset; break; } } } c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ yyg->yy_hold_char = *++yyg->yy_c_buf_p; if ( c == '\n' ) do{ yylineno++; yycolumn=0; }while(0) ; return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * @param yyscanner The scanner object. * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (yyscanner); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer( yyin, YY_BUF_SIZE , yyscanner); } yy_init_buffer( YY_CURRENT_BUFFER, input_file , yyscanner); yy_load_buffer_state( yyscanner ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * @param yyscanner The scanner object. */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (yyscanner); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *yyg->yy_c_buf_p = yyg->yy_hold_char; YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( yyscanner ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ yyg->yy_did_buffer_switch_on_eof = 1; } static void yy_load_buffer_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; yyg->yy_hold_char = *yyg->yy_c_buf_p; } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * @param yyscanner The scanner object. * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) , yyscanner ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer( b, file , yyscanner); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * @param yyscanner The scanner object. */ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree( (void *) b->yy_ch_buf , yyscanner ); yyfree( (void *) b , yyscanner ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) { int oerrno = errno; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_flush_buffer( b , yyscanner); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * @param yyscanner The scanner object. */ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( yyscanner ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * @param yyscanner The scanner object. */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (new_buffer == NULL) return; yyensure_buffer_stack(yyscanner); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *yyg->yy_c_buf_p = yyg->yy_hold_char; YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) yyg->yy_buffer_stack_top++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( yyscanner ); yyg->yy_did_buffer_switch_on_eof = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * @param yyscanner The scanner object. */ void yypop_buffer_state (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER , yyscanner); YY_CURRENT_BUFFER_LVALUE = NULL; if (yyg->yy_buffer_stack_top > 0) --yyg->yy_buffer_stack_top; if (YY_CURRENT_BUFFER) { yy_load_buffer_state( yyscanner ); yyg->yy_did_buffer_switch_on_eof = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (yyscan_t yyscanner) { yy_size_t num_to_alloc; struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (!yyg->yy_buffer_stack) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); if ( ! yyg->yy_buffer_stack ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); yyg->yy_buffer_stack_max = num_to_alloc; yyg->yy_buffer_stack_top = 0; return; } if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ /* Increase the buffer to prepare for a possible push. */ yy_size_t grow_size = 8 /* arbitrary grow size */; num_to_alloc = yyg->yy_buffer_stack_max + grow_size; yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc (yyg->yy_buffer_stack, num_to_alloc * sizeof(struct yy_buffer_state*) , yyscanner); if ( ! yyg->yy_buffer_stack ) YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); /* zero only the new slots.*/ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); yyg->yy_buffer_stack_max = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return NULL; b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) , yyscanner ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = NULL; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer( b , yyscanner ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * @param yyscanner The scanner object. * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (const char * yystr , yyscan_t yyscanner) { return yy_scan_bytes( yystr, (int) strlen(yystr) , yyscanner); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param yybytes the byte buffer to scan * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * @param yyscanner The scanner object. * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len , yyscan_t yyscanner) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = (yy_size_t) (_yybytes_len + 2); buf = (char *) yyalloc( n , yyscanner ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer( buf, n , yyscanner); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yynoreturn yy_fatal_error (const char* msg , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = yyg->yy_hold_char; \ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ yyg->yy_hold_char = *yyg->yy_c_buf_p; \ *yyg->yy_c_buf_p = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the user-defined data for this scanner. * @param yyscanner The scanner object. */ YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyextra; } /** Get the current line number. * @param yyscanner The scanner object. */ int yyget_lineno (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (! YY_CURRENT_BUFFER) return 0; return yylineno; } /** Get the current column number. * @param yyscanner The scanner object. */ int yyget_column (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; if (! YY_CURRENT_BUFFER) return 0; return yycolumn; } /** Get the input stream. * @param yyscanner The scanner object. */ FILE *yyget_in (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyin; } /** Get the output stream. * @param yyscanner The scanner object. */ FILE *yyget_out (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyout; } /** Get the length of the current token. * @param yyscanner The scanner object. */ int yyget_leng (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yyleng; } /** Get the current token. * @param yyscanner The scanner object. */ char *yyget_text (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yytext; } /** Set the user-defined data. This data is never touched by the scanner. * @param user_defined The data to be associated with this scanner. * @param yyscanner The scanner object. */ void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyextra = user_defined ; } /** Set the current line number. * @param _line_number line number * @param yyscanner The scanner object. */ void yyset_lineno (int _line_number , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* lineno is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) YY_FATAL_ERROR( "yyset_lineno called with no buffer" ); yylineno = _line_number; } /** Set the current column. * @param _column_no column number * @param yyscanner The scanner object. */ void yyset_column (int _column_no , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* column is only valid if an input buffer exists. */ if (! YY_CURRENT_BUFFER ) YY_FATAL_ERROR( "yyset_column called with no buffer" ); yycolumn = _column_no; } /** Set the input stream. This does not discard the current * input buffer. * @param _in_str A readable stream. * @param yyscanner The scanner object. * @see yy_switch_to_buffer */ void yyset_in (FILE * _in_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyin = _in_str ; } void yyset_out (FILE * _out_str , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yyout = _out_str ; } int yyget_debug (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yy_flex_debug; } void yyset_debug (int _bdebug , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yy_flex_debug = _bdebug ; } /* Accessor methods for yylval and yylloc */ YYSTYPE * yyget_lval (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; return yylval; } void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; yylval = yylval_param; } /* User-visible API */ /* yylex_init is special because it creates the scanner itself, so it is * the ONLY reentrant function that doesn't take the scanner as the last argument. * That's why we explicitly handle the declaration, instead of using our macros. */ int yylex_init(yyscan_t* ptr_yy_globals) { if (ptr_yy_globals == NULL){ errno = EINVAL; return 1; } *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL ); if (*ptr_yy_globals == NULL){ errno = ENOMEM; return 1; } /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); return yy_init_globals ( *ptr_yy_globals ); } /* yylex_init_extra has the same functionality as yylex_init, but follows the * convention of taking the scanner as the last argument. Note however, that * this is a *pointer* to a scanner, as it will be allocated by this call (and * is the reason, too, why this function also must handle its own declaration). * The user defined value in the first argument will be available to yyalloc in * the yyextra field. */ int yylex_init_extra( YY_EXTRA_TYPE yy_user_defined, yyscan_t* ptr_yy_globals ) { struct yyguts_t dummy_yyguts; yyset_extra (yy_user_defined, &dummy_yyguts); if (ptr_yy_globals == NULL){ errno = EINVAL; return 1; } *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); if (*ptr_yy_globals == NULL){ errno = ENOMEM; return 1; } /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); yyset_extra (yy_user_defined, *ptr_yy_globals); return yy_init_globals ( *ptr_yy_globals ); } static int yy_init_globals (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ yyg->yy_buffer_stack = NULL; yyg->yy_buffer_stack_top = 0; yyg->yy_buffer_stack_max = 0; yyg->yy_c_buf_p = NULL; yyg->yy_init = 0; yyg->yy_start = 0; yyg->yy_start_stack_ptr = 0; yyg->yy_start_stack_depth = 0; yyg->yy_start_stack = NULL; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = NULL; yyout = NULL; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer( YY_CURRENT_BUFFER , yyscanner ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(yyscanner); } /* Destroy the stack itself. */ yyfree(yyg->yy_buffer_stack , yyscanner); yyg->yy_buffer_stack = NULL; /* Destroy the start condition stack. */ yyfree( yyg->yy_start_stack , yyscanner ); yyg->yy_start_stack = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( yyscanner); /* Destroy the main struct (reentrant only). */ yyfree ( yyscanner , yyscanner ); yyscanner = NULL; return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, const char * s2, int n , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (const char * s , yyscan_t yyscanner) { int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; return malloc(size); } void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return realloc(ptr, size); } void yyfree (void * ptr , yyscan_t yyscanner) { struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; (void)yyg; free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" #line 496 "libyara/re_lexer.l" int escaped_char_value( char* text, uint8_t* value, bool strict_escape) { unsigned int hex_value; char hex[3]; assert(text[0] == '\\'); switch(text[1]) { case 'x': if (!isxdigit(text[2]) || !isxdigit(text[3])) return 0; hex[0] = text[2]; hex[1] = text[3]; hex[2] = '\0'; sscanf(hex, "%x", &hex_value); *value = (uint8_t) hex_value; break; case 'n': *value = '\n'; break; case 't': *value = '\t'; break; case 'r': *value = '\r'; break; case 'f': *value = '\f'; break; case 'a': *value = '\a'; break; // Support metacharacters in escape sequences case '\\': case '^': case '$': case '.': case '|': case '(': case ')': case '[': case ']': // Support other special characters that are used in rules and need to be escaped case '*': case '+': case '?': case '"': case '\'': case '-': case '{': case '}': case '#': case ':': case '_': case '=': case '/': case '!': case ',': case '@': case '<': case '>': case '~': case '&': case '%': *value = text[1]; break; default: *value = text[1]; if (strict_escape) return UNKNOWN_ESCAPE_SEQUENCE; return VALID_ESCAPE_SEQUENCE; } return VALID_ESCAPE_SEQUENCE; } #ifdef __cplusplus #define RE_YY_INPUT yyinput #else #define RE_YY_INPUT input #endif int read_escaped_char( yyscan_t yyscanner, uint8_t* escaped_char, bool strict_escape) { char text[4] = {0, 0, 0, 0}; text[0] = '\\'; text[1] = RE_YY_INPUT(yyscanner); if (text[1] == EOF || text[1] == 0) return 0; if (text[1] == 'x') { text[2] = RE_YY_INPUT(yyscanner); if (text[2] == EOF || text[2] == 0) return 0; text[3] = RE_YY_INPUT(yyscanner); if (text[3] == EOF || text[3] == 0) return 0; } return escaped_char_value(text, escaped_char, strict_escape); } // // yyfatal (actually named re_yyfatal because of the '%option prefix="re_yy"' // directive) is called when a fatal error occurs in the parser. When this // happens we are deep inside the parsing logic generated by flex/bison and // the only way to exit gracefully from there is using setjmp/longjmp. // void yyfatal( yyscan_t yyscanner, const char *error_message) { jmp_buf* recovery_trampoline = (jmp_buf*) yr_thread_storage_get_value( &yr_yyfatal_trampoline_tls); longjmp(*recovery_trampoline, 1); } void yyerror( yyscan_t yyscanner, RE_LEX_ENVIRONMENT* lex_env, const char *error_message) { // if lex_env->last_error was set to some error code before // don't overwrite it, we are interested in the first error, not in // subsequent errors like "syntax error, unexpected $end" caused by // early parser termination. if (lex_env->last_error == ERROR_SUCCESS || lex_env->last_error == ERROR_UNKNOWN_ESCAPE_SEQUENCE) { lex_env->last_error = ERROR_INVALID_REGULAR_EXPRESSION; strlcpy( lex_env->last_error_message, error_message, sizeof(lex_env->last_error_message)); } } void yywarning( yyscan_t yyscanner, RE_LEX_ENVIRONMENT* lex_env, const char *error_message) { // Do not overwrite Errors // print out warning only if there is not any other error beforehand if (lex_env->last_error == ERROR_SUCCESS) { lex_env->last_error = ERROR_UNKNOWN_ESCAPE_SEQUENCE; strlcpy( lex_env->last_error_message, error_message, sizeof(lex_env->last_error_message)); } } int yr_parse_re_string( const char* re_string, RE_AST** re_ast, RE_ERROR* error, int flags) { yyscan_t yyscanner; jmp_buf recovery_trampoline; RE_LEX_ENVIRONMENT lex_env; lex_env.last_error = ERROR_SUCCESS; if (flags & RE_PARSER_FLAG_ENABLE_STRICT_ESCAPE_SEQUENCES) lex_env.strict_escape = true; else lex_env.strict_escape = false; lex_env.last_error_message[0] = '\0'; yr_thread_storage_set_value( &yr_yyfatal_trampoline_tls, &recovery_trampoline); // setjmp returns a non-zero value only when we are returning to this // point via a call to longjmp to the recovery trampoline. if (setjmp(recovery_trampoline) != 0) return ERROR_INTERNAL_FATAL_ERROR; FAIL_ON_ERROR(yr_re_ast_create(re_ast)); if (yylex_init(&yyscanner) != 0) { yr_re_ast_destroy(*re_ast); *re_ast = NULL; return ERROR_INSUFFICIENT_MEMORY; } yyset_extra(*re_ast, yyscanner); yy_scan_string(re_string, yyscanner); yyparse(yyscanner, &lex_env); yylex_destroy(yyscanner); if (lex_env.last_error != ERROR_SUCCESS) { if (lex_env.last_error != ERROR_UNKNOWN_ESCAPE_SEQUENCE) { yr_re_ast_destroy(*re_ast); *re_ast = NULL; } strlcpy( error->message, lex_env.last_error_message, sizeof(error->message)); return lex_env.last_error; } return ERROR_SUCCESS; } yara-4.5.3/libyara/re_lexer.l000066400000000000000000000362551501365277300161100ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Lexical analyzer for regular expressions */ %{ /* Disable warnings for unused functions in this file. As we redefine YY_FATAL_ERROR macro to use our own function re_yyfatal, the yy_fatal_error function generated by Flex is not actually used, causing a compiler warning. Flex doesn't offer any options to remove the yy_fatal_error function. When they include something like %option noyy_fatal_error as they do with noyywrap then we can remove this pragma. */ #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wunused-function" #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #define snprintf _snprintf #endif // Bitmap with 1 bit for each of the 256 characters in the ASCII table. The bit // is set to 1 if the corresponding character is alphanumeric or 0 if otherwise. static uint8_t word_chars[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x03, 0xFE, 0xFF, 0xFF, 0x87, 0xFE, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // Bitmap with 1 bit for each of the 256 characters in the ASCII table. The bit // is set to 1 if the corresponding character is considered a space. Space // characters include horizontal and vertical tabs, carriage return, new line // and form feed (\t, \v, \r, \n, \f). static uint8_t space_chars[] = { 0x00, 0x3E, 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 }; int escaped_char_value( char* text, uint8_t* value, bool strict_escape); int read_escaped_char( yyscan_t yyscanner, uint8_t* escaped_char, bool strict_escape); %} %option reentrant bison-bridge %option noyywrap %option nounistd %option nounput %option never-interactive %option yylineno %option prefix="re_yy" %option outfile="lex.yy.c" %option verbose %option warn %x char_class digit [0-9] hex_digit [0-9a-fA-F] %% \{{digit}*[ ]*,[ ]*{digit}*\} { // Examples: {3,8} {3, 8}, {3 ,8} {3 , 8} {0,5} {,5} {7,} int hi_bound; int lo_bound = atoi(yytext + 1); char* comma = strchr(yytext, ','); char* hi_bound_ptr = comma + 1; // Skip spaces after the comma, if any. while (*hi_bound_ptr == ' ') hi_bound_ptr++; if (*hi_bound_ptr == '}') hi_bound = RE_MAX_RANGE; else hi_bound = atoi(hi_bound_ptr); if (hi_bound > RE_MAX_RANGE) { yyerror(yyscanner, lex_env, "repeat interval too large"); yyterminate(); } if (hi_bound < lo_bound || hi_bound < 0 || lo_bound < 0) { yyerror(yyscanner, lex_env, "bad repeat interval"); yyterminate(); } yylval->range = (hi_bound << 16) | lo_bound; return _RANGE_; } \{{digit}+\} { // Example: {10} int value = atoi(yytext + 1); // atoi can return a negative value if the input string represents a number // too large to fit in an integer. if (value > RE_MAX_RANGE || value < 0) { yyerror(yyscanner, lex_env, "repeat interval too large"); yyterminate(); } yylval->range = (value << 16) | value; return _RANGE_; } \[\^ { // Start of a negated character class. Example: [^abcd] BEGIN(char_class); memset(LEX_ENV->re_class.bitmap, 0, 32); LEX_ENV->re_class.negated = true; } \[\^\] { // Start of character negated class containing a ]. // Example: [^]abc] this must be interpreted as a class // not matching ], a, b, nor c BEGIN(char_class); memset(LEX_ENV->re_class.bitmap, 0, 32); LEX_ENV->re_class.negated = true; LEX_ENV->re_class.bitmap[']' / 8] |= 1 << ']' % 8; } \[\] { // Start of character class containing a ]. // Example: []abc] this must be interpreted as a class // matching ], a, b, or c. BEGIN(char_class); memset(LEX_ENV->re_class.bitmap, 0, 32); LEX_ENV->re_class.negated = false; LEX_ENV->re_class.bitmap[']' / 8] |= 1 << ']' % 8; } \[ { // Start of character class. Example: [abcd] BEGIN(char_class); memset(LEX_ENV->re_class.bitmap, 0, 32); LEX_ENV->re_class.negated = false; } [^\\\[\(\)\|\$\.\^\+\*\?] { // Any non-special character is passed as a CHAR token to the scanner. yylval->integer = yytext[0]; return _CHAR_; } \\w { return _WORD_CHAR_; } \\W { return _NON_WORD_CHAR_; } \\s { return _SPACE_; } \\S { return _NON_SPACE_; } \\d { return _DIGIT_; } \\D { return _NON_DIGIT_; } \\b { return _WORD_BOUNDARY_; } \\B { return _NON_WORD_BOUNDARY_; } \\{digit}+ { yyerror(yyscanner, lex_env, "backreferences are not allowed"); yyterminate(); } \\ { uint8_t c; int return_code; return_code = read_escaped_char(yyscanner, &c, LEX_ENV->strict_escape); if (return_code == VALID_ESCAPE_SEQUENCE) { yylval->integer = c; return _CHAR_; } else if (return_code == UNKNOWN_ESCAPE_SEQUENCE) { yywarning(yyscanner, lex_env, "unknown escape sequence"); yylval->integer = c; return _CHAR_; } else { yyerror(yyscanner, lex_env, "illegal escape sequence"); yyterminate(); } } \] { // End of character class. yylval->re_class = (RE_CLASS*) yr_malloc(sizeof(RE_CLASS)); memcpy(yylval->re_class->bitmap, LEX_ENV->re_class.bitmap, 32); yylval->re_class->negated = LEX_ENV->re_class.negated; BEGIN(INITIAL); return _CLASS_; } (\\x{hex_digit}{2}|\\.|[^]\\])-[^]] { // A range inside a character class. The regexp is... // // ( \x{hex_digit}{2} Hex digit (i.e: \x01) ... // | \. ...or any escaped character (i.e. \\, \-) ... // | [^]\] ...or any character except ] and \ ... // ) // - ... followed by - // [^]] ... followed by any character except ] // // Some examples: // // [abc0-9] // ^-^ matching range 0-9 // // [a-za-] // ^-^- matching range a-z // // [\.-a] // ^--^- matching range \.-a // uint16_t c; uint8_t start = yytext[0]; uint8_t end = yytext[2]; if (start == '\\') { if (!escaped_char_value(yytext, &start, LEX_ENV->strict_escape)) { yyerror(yyscanner, lex_env, "illegal escape sequence"); yyterminate(); } if (yytext[1] == 'x') end = yytext[5]; else end = yytext[3]; } if (end == '\\') { if (!read_escaped_char(yyscanner, &end, LEX_ENV->strict_escape)) { yyerror(yyscanner, lex_env, "illegal escape sequence"); yyterminate(); } } if (end < start) { yyerror(yyscanner, lex_env, "bad character range"); yyterminate(); } for (c = start; c <= end; c++) { LEX_ENV->re_class.bitmap[c / 8] |= 1 << c % 8; } } \\w { for (int i = 0; i < 32; i++) LEX_ENV->re_class.bitmap[i] |= word_chars[i]; } \\W { for (int i = 0; i < 32; i++) LEX_ENV->re_class.bitmap[i] |= ~word_chars[i]; } \\s { for (int i = 0; i < 32; i++) LEX_ENV->re_class.bitmap[i] |= space_chars[i]; } \\S { for (int i = 0; i < 32; i++) LEX_ENV->re_class.bitmap[i] |= ~space_chars[i]; } \\d { for (char c = '0'; c <= '9'; c++) LEX_ENV->re_class.bitmap[c / 8] |= 1 << c % 8; } \\D { for (int i = 0; i < 32; i++) { // digits 0-7 are in the sixth byte of the vector, let that byte alone if (i == 6) continue; // digits 8 and 9 are the lowest two bits in the seventh byte of the // vector, let those bits alone. if (i == 7) LEX_ENV->re_class.bitmap[i] |= 0xFC; else LEX_ENV->re_class.bitmap[i] = 0xFF; } } \\ { uint8_t c; int return_code; return_code = read_escaped_char(yyscanner, &c, LEX_ENV->strict_escape); if (return_code == VALID_ESCAPE_SEQUENCE) { LEX_ENV->re_class.bitmap[c / 8] |= 1 << c % 8; } else if (return_code == UNKNOWN_ESCAPE_SEQUENCE) { yywarning(yyscanner, lex_env, "unknown escape sequence"); LEX_ENV->re_class.bitmap[c / 8] |= 1 << c % 8; } else { yyerror(yyscanner, lex_env, "illegal escape sequence"); yyterminate(); } } . { if (yytext[0] >= 32 && yytext[0] < 127) { // A character class (i.e: [0-9a-f]) is represented by a 256-bits vector, // here we set to 1 the vector's bit corresponding to the input character. LEX_ENV->re_class.bitmap[yytext[0] / 8] |= 1 << yytext[0] % 8; } else { yyerror(yyscanner, lex_env, "non-ascii character"); yyterminate(); } } <> { // End of regexp reached while scanning a character class. yyerror(yyscanner, lex_env, "missing terminating ] for character class"); yyterminate(); } . { if (yytext[0] >= 32 && yytext[0] < 127) { return yytext[0]; } else { yyerror(yyscanner, lex_env, "non-ascii character"); yyterminate(); } } <> { yyterminate(); } %% int escaped_char_value( char* text, uint8_t* value, bool strict_escape) { unsigned int hex_value; char hex[3]; assert(text[0] == '\\'); switch(text[1]) { case 'x': if (!isxdigit(text[2]) || !isxdigit(text[3])) return 0; hex[0] = text[2]; hex[1] = text[3]; hex[2] = '\0'; sscanf(hex, "%x", &hex_value); *value = (uint8_t) hex_value; break; case 'n': *value = '\n'; break; case 't': *value = '\t'; break; case 'r': *value = '\r'; break; case 'f': *value = '\f'; break; case 'a': *value = '\a'; break; // Support metacharacters in escape sequences case '\\': case '^': case '$': case '.': case '|': case '(': case ')': case '[': case ']': // Support other special characters that are used in rules and need to be escaped case '*': case '+': case '?': case '"': case '\'': case '-': case '{': case '}': case '#': case ':': case '_': case '=': case '/': case '!': case ',': case '@': case '<': case '>': case '~': case '&': case '%': *value = text[1]; break; default: *value = text[1]; if (strict_escape) return UNKNOWN_ESCAPE_SEQUENCE; return VALID_ESCAPE_SEQUENCE; } return VALID_ESCAPE_SEQUENCE; } #ifdef __cplusplus #define RE_YY_INPUT yyinput #else #define RE_YY_INPUT input #endif int read_escaped_char( yyscan_t yyscanner, uint8_t* escaped_char, bool strict_escape) { char text[4] = {0, 0, 0, 0}; text[0] = '\\'; text[1] = RE_YY_INPUT(yyscanner); if (text[1] == EOF || text[1] == 0) return 0; if (text[1] == 'x') { text[2] = RE_YY_INPUT(yyscanner); if (text[2] == EOF || text[2] == 0) return 0; text[3] = RE_YY_INPUT(yyscanner); if (text[3] == EOF || text[3] == 0) return 0; } return escaped_char_value(text, escaped_char, strict_escape); } // // yyfatal (actually named re_yyfatal because of the '%option prefix="re_yy"' // directive) is called when a fatal error occurs in the parser. When this // happens we are deep inside the parsing logic generated by flex/bison and // the only way to exit gracefully from there is using setjmp/longjmp. // void yyfatal( yyscan_t yyscanner, const char *error_message) { jmp_buf* recovery_trampoline = (jmp_buf*) yr_thread_storage_get_value( &yr_yyfatal_trampoline_tls); longjmp(*recovery_trampoline, 1); } void yyerror( yyscan_t yyscanner, RE_LEX_ENVIRONMENT* lex_env, const char *error_message) { // if lex_env->last_error was set to some error code before // don't overwrite it, we are interested in the first error, not in // subsequent errors like "syntax error, unexpected $end" caused by // early parser termination. if (lex_env->last_error == ERROR_SUCCESS || lex_env->last_error == ERROR_UNKNOWN_ESCAPE_SEQUENCE) { lex_env->last_error = ERROR_INVALID_REGULAR_EXPRESSION; strlcpy( lex_env->last_error_message, error_message, sizeof(lex_env->last_error_message)); } } void yywarning( yyscan_t yyscanner, RE_LEX_ENVIRONMENT* lex_env, const char *error_message) { // Do not overwrite Errors // print out warning only if there is not any other error beforehand if (lex_env->last_error == ERROR_SUCCESS) { lex_env->last_error = ERROR_UNKNOWN_ESCAPE_SEQUENCE; strlcpy( lex_env->last_error_message, error_message, sizeof(lex_env->last_error_message)); } } int yr_parse_re_string( const char* re_string, RE_AST** re_ast, RE_ERROR* error, int flags) { yyscan_t yyscanner; jmp_buf recovery_trampoline; RE_LEX_ENVIRONMENT lex_env; lex_env.last_error = ERROR_SUCCESS; if (flags & RE_PARSER_FLAG_ENABLE_STRICT_ESCAPE_SEQUENCES) lex_env.strict_escape = true; else lex_env.strict_escape = false; lex_env.last_error_message[0] = '\0'; yr_thread_storage_set_value( &yr_yyfatal_trampoline_tls, &recovery_trampoline); // setjmp returns a non-zero value only when we are returning to this // point via a call to longjmp to the recovery trampoline. if (setjmp(recovery_trampoline) != 0) return ERROR_INTERNAL_FATAL_ERROR; FAIL_ON_ERROR(yr_re_ast_create(re_ast)); if (yylex_init(&yyscanner) != 0) { yr_re_ast_destroy(*re_ast); *re_ast = NULL; return ERROR_INSUFFICIENT_MEMORY; } yyset_extra(*re_ast, yyscanner); yy_scan_string(re_string, yyscanner); yyparse(yyscanner, &lex_env); yylex_destroy(yyscanner); if (lex_env.last_error != ERROR_SUCCESS) { if (lex_env.last_error != ERROR_UNKNOWN_ESCAPE_SEQUENCE) { yr_re_ast_destroy(*re_ast); *re_ast = NULL; } strlcpy( error->message, lex_env.last_error_message, sizeof(error->message)); return lex_env.last_error; } return ERROR_SUCCESS; } yara-4.5.3/libyara/rules.c000066400000000000000000000331741501365277300154210ustar00rootroot00000000000000/* Copyright (c) 2013. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include YR_API int yr_rules_define_integer_variable( YR_RULES* rules, const char* identifier, int64_t value) { YR_EXTERNAL_VARIABLE* external; if (identifier == NULL) return ERROR_INVALID_ARGUMENT; external = rules->ext_vars_table; while (!EXTERNAL_VARIABLE_IS_NULL(external)) { if (strcmp(external->identifier, identifier) == 0) { if (external->type != EXTERNAL_VARIABLE_TYPE_INTEGER) return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE; external->value.i = value; return ERROR_SUCCESS; } external++; } return ERROR_INVALID_ARGUMENT; } YR_API int yr_rules_define_boolean_variable( YR_RULES* rules, const char* identifier, int value) { YR_EXTERNAL_VARIABLE* external; if (identifier == NULL) return ERROR_INVALID_ARGUMENT; external = rules->ext_vars_table; while (!EXTERNAL_VARIABLE_IS_NULL(external)) { if (strcmp(external->identifier, identifier) == 0) { if (external->type != EXTERNAL_VARIABLE_TYPE_BOOLEAN) return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE; external->value.i = value; return ERROR_SUCCESS; } external++; } return ERROR_INVALID_ARGUMENT; } YR_API int yr_rules_define_float_variable( YR_RULES* rules, const char* identifier, double value) { YR_EXTERNAL_VARIABLE* external; if (identifier == NULL) return ERROR_INVALID_ARGUMENT; external = rules->ext_vars_table; while (!EXTERNAL_VARIABLE_IS_NULL(external)) { if (strcmp(external->identifier, identifier) == 0) { if (external->type != EXTERNAL_VARIABLE_TYPE_FLOAT) return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE; external->value.f = value; return ERROR_SUCCESS; } external++; } return ERROR_INVALID_ARGUMENT; } YR_API int yr_rules_define_string_variable( YR_RULES* rules, const char* identifier, const char* value) { YR_EXTERNAL_VARIABLE* external; if (identifier == NULL || value == NULL) return ERROR_INVALID_ARGUMENT; external = rules->ext_vars_table; while (!EXTERNAL_VARIABLE_IS_NULL(external)) { if (strcmp(external->identifier, identifier) == 0) { if (external->type != EXTERNAL_VARIABLE_TYPE_STRING && external->type != EXTERNAL_VARIABLE_TYPE_MALLOC_STRING) return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE; if (external->type == EXTERNAL_VARIABLE_TYPE_MALLOC_STRING && external->value.s != NULL) { yr_free(external->value.s); } external->type = EXTERNAL_VARIABLE_TYPE_MALLOC_STRING; external->value.s = yr_strdup(value); if (external->value.s == NULL) return ERROR_INSUFFICIENT_MEMORY; else return ERROR_SUCCESS; } external++; } return ERROR_INVALID_ARGUMENT; } YR_API int yr_rules_scan_mem_blocks( YR_RULES* rules, YR_MEMORY_BLOCK_ITERATOR* iterator, int flags, YR_CALLBACK_FUNC callback, void* user_data, int timeout) { YR_SCANNER* scanner; int result; FAIL_ON_ERROR(yr_scanner_create(rules, &scanner)); yr_scanner_set_callback(scanner, callback, user_data); yr_scanner_set_timeout(scanner, timeout); yr_scanner_set_flags(scanner, flags); result = yr_scanner_scan_mem_blocks(scanner, iterator); yr_scanner_destroy(scanner); return result; } YR_API int yr_rules_scan_mem( YR_RULES* rules, const uint8_t* buffer, size_t buffer_size, int flags, YR_CALLBACK_FUNC callback, void* user_data, int timeout) { YR_DEBUG_FPRINTF( 2, stderr, "+ %s(buffer=%p buffer_size=%zu timeout=%d) {\n", __FUNCTION__, buffer, buffer_size, timeout); YR_SCANNER* scanner; int result = ERROR_INTERNAL_FATAL_ERROR; GOTO_EXIT_ON_ERROR(yr_scanner_create(rules, &scanner)); yr_scanner_set_callback(scanner, callback, user_data); yr_scanner_set_timeout(scanner, timeout); yr_scanner_set_flags(scanner, flags); result = yr_scanner_scan_mem(scanner, buffer, buffer_size); yr_scanner_destroy(scanner); _exit: YR_DEBUG_FPRINTF( 2, stderr, "" "} = %d AKA %s // %s()\n", result, yr_debug_error_as_string(result), __FUNCTION__); return result; } YR_API int yr_rules_scan_file( YR_RULES* rules, const char* filename, int flags, YR_CALLBACK_FUNC callback, void* user_data, int timeout) { YR_MAPPED_FILE mfile; int result = yr_filemap_map(filename, &mfile); if (result == ERROR_SUCCESS) { result = yr_rules_scan_mem( rules, mfile.data, mfile.size, flags, callback, user_data, timeout); yr_filemap_unmap(&mfile); } return result; } YR_API int yr_rules_scan_fd( YR_RULES* rules, YR_FILE_DESCRIPTOR fd, int flags, YR_CALLBACK_FUNC callback, void* user_data, int timeout) { YR_MAPPED_FILE mfile; int result = yr_filemap_map_fd(fd, 0, 0, &mfile); if (result == ERROR_SUCCESS) { result = yr_rules_scan_mem( rules, mfile.data, mfile.size, flags, callback, user_data, timeout); yr_filemap_unmap_fd(&mfile); } return result; } YR_API int yr_rules_scan_proc( YR_RULES* rules, int pid, int flags, YR_CALLBACK_FUNC callback, void* user_data, int timeout) { YR_DEBUG_FPRINTF( 2, stderr, "+ %s(pid=%d timeout=%d) {\n", __FUNCTION__, pid, timeout); YR_MEMORY_BLOCK_ITERATOR iterator; int result = yr_process_open_iterator(pid, &iterator); if (result == ERROR_SUCCESS) { result = yr_rules_scan_mem_blocks( rules, &iterator, flags | SCAN_FLAGS_PROCESS_MEMORY, callback, user_data, timeout); yr_process_close_iterator(&iterator); } YR_DEBUG_FPRINTF( 2, stderr, "} = %d AKA %s // %s()\n", result, yr_debug_error_as_string(result), __FUNCTION__); return result; } int yr_rules_from_arena(YR_ARENA* arena, YR_RULES** rules) { YR_SUMMARY* summary = (YR_SUMMARY*) yr_arena_get_ptr( arena, YR_SUMMARY_SECTION, 0); if (summary == NULL) return ERROR_CORRUPT_FILE; YR_RULES* new_rules = (YR_RULES*) yr_malloc(sizeof(YR_RULES)); if (new_rules == NULL) return ERROR_INSUFFICIENT_MEMORY; new_rules->no_required_strings = (YR_BITMASK*) yr_calloc( sizeof(YR_BITMASK), YR_BITMASK_SIZE(summary->num_rules)); if (new_rules->no_required_strings == NULL) { yr_free(new_rules); return ERROR_INSUFFICIENT_MEMORY; } // Now YR_RULES relies on this arena, let's increment the arena's // reference count so that if the original owner of the arena calls // yr_arena_destroy the arena is not destroyed. yr_arena_acquire(arena); new_rules->arena = arena; new_rules->num_rules = summary->num_rules; new_rules->num_strings = summary->num_strings; new_rules->num_namespaces = summary->num_namespaces; new_rules->rules_table = yr_arena_get_ptr(arena, YR_RULES_TABLE, 0); new_rules->strings_table = yr_arena_get_ptr(arena, YR_STRINGS_TABLE, 0); new_rules->ext_vars_table = yr_arena_get_ptr( arena, YR_EXTERNAL_VARIABLES_TABLE, 0); new_rules->ac_transition_table = yr_arena_get_ptr( arena, YR_AC_TRANSITION_TABLE, 0); new_rules->ac_match_table = yr_arena_get_ptr( arena, YR_AC_STATE_MATCHES_TABLE, 0); new_rules->ac_match_pool = yr_arena_get_ptr( arena, YR_AC_STATE_MATCHES_POOL, 0); new_rules->code_start = yr_arena_get_ptr(arena, YR_CODE_SECTION, 0); // If a rule has no required_strings, this means that the condition might // evaluate to true without any matching strings, and we therefore have to // mark it as "to be evaluated" from the beginning. for (int i = 0; i < new_rules->num_rules; i++) { if (new_rules->rules_table[i].required_strings == 0) yr_bitmask_set(new_rules->no_required_strings, i); } *rules = new_rules; return ERROR_SUCCESS; } YR_API int yr_rules_load_stream(YR_STREAM* stream, YR_RULES** rules) { YR_ARENA* arena; // Load the arena's data the stream. We are the owners of the arena. FAIL_ON_ERROR(yr_arena_load_stream(stream, &arena)); // Create the YR_RULES object from the arena, this makes YR_RULES owner // of the arena too. FAIL_ON_ERROR(yr_rules_from_arena(arena, rules)); // Release our ownership so that YR_RULES is the single owner. This way the // arena is destroyed when YR_RULES is destroyed. yr_arena_release(arena); return ERROR_SUCCESS; } YR_API int yr_rules_load(const char* filename, YR_RULES** rules) { int result; YR_STREAM stream; FILE* fh = fopen(filename, "rb"); if (fh == NULL) return ERROR_COULD_NOT_OPEN_FILE; stream.user_data = fh; stream.read = (YR_STREAM_READ_FUNC) fread; result = yr_rules_load_stream(&stream, rules); fclose(fh); return result; } YR_API int yr_rules_save_stream(YR_RULES* rules, YR_STREAM* stream) { return yr_arena_save_stream(rules->arena, stream); } YR_API int yr_rules_save(YR_RULES* rules, const char* filename) { int result; YR_STREAM stream; FILE* fh = fopen(filename, "wb"); if (fh == NULL) return ERROR_COULD_NOT_OPEN_FILE; stream.user_data = fh; stream.write = (YR_STREAM_WRITE_FUNC) fwrite; result = yr_rules_save_stream(rules, &stream); fclose(fh); return result; } static int _uint32_cmp(const void* a, const void* b) { return (*(uint32_t*) a - *(uint32_t*) b); } YR_API int yr_rules_get_stats(YR_RULES* rules, YR_RULES_STATS* stats) { memset(stats, 0, sizeof(YR_RULES_STATS)); stats->ac_tables_size = yr_arena_get_current_offset( rules->arena, YR_AC_TRANSITION_TABLE) / sizeof(YR_AC_TRANSITION); uint32_t* match_list_lengths = (uint32_t*) yr_malloc( sizeof(uint32_t) * stats->ac_tables_size); if (match_list_lengths == NULL) return ERROR_INSUFFICIENT_MEMORY; stats->num_rules = rules->num_rules; stats->num_strings = rules->num_strings; float match_list_length_sum = 0; int c = 0; for (uint32_t i = 0; i < stats->ac_tables_size; i++) { int match_list_length = 0; if (rules->ac_match_table[i] != 0) { YR_AC_MATCH* m = &rules->ac_match_pool[rules->ac_match_table[i] - 1]; while (m != NULL) { match_list_length++; stats->ac_matches++; m = m->next; } } if (i == 0) stats->ac_root_match_list_length = match_list_length; match_list_length_sum += match_list_length; if (match_list_length > 0) { match_list_lengths[c] = match_list_length; c++; } } if (c == 0) { yr_free(match_list_lengths); return ERROR_SUCCESS; } // sort match_list_lengths in increasing order for computing percentiles. qsort(match_list_lengths, c, sizeof(match_list_lengths[0]), _uint32_cmp); for (int i = 0; i < 100; i++) { if (i < c) stats->top_ac_match_list_lengths[i] = match_list_lengths[c - i - 1]; else stats->top_ac_match_list_lengths[i] = 0; } stats->ac_average_match_list_length = match_list_length_sum / c; stats->ac_match_list_length_pctls[0] = match_list_lengths[0]; stats->ac_match_list_length_pctls[100] = match_list_lengths[c - 1]; for (int i = 1; i < 100; i++) stats->ac_match_list_length_pctls[i] = match_list_lengths[(c * i) / 100]; yr_free(match_list_lengths); return ERROR_SUCCESS; } YR_API int yr_rules_destroy(YR_RULES* rules) { YR_EXTERNAL_VARIABLE* external = rules->ext_vars_table; while (!EXTERNAL_VARIABLE_IS_NULL(external)) { if (external->type == EXTERNAL_VARIABLE_TYPE_MALLOC_STRING) yr_free(external->value.s); external++; } yr_free(rules->no_required_strings); yr_arena_release(rules->arena); yr_free(rules); return ERROR_SUCCESS; } YR_API void yr_rule_disable(YR_RULE* rule) { YR_STRING* string; rule->flags |= RULE_FLAGS_DISABLED; yr_rule_strings_foreach(rule, string) { string->flags |= STRING_FLAGS_DISABLED; } } YR_API void yr_rule_enable(YR_RULE* rule) { YR_STRING* string; rule->flags &= ~RULE_FLAGS_DISABLED; yr_rule_strings_foreach(rule, string) { string->flags &= ~STRING_FLAGS_DISABLED; } } yara-4.5.3/libyara/scan.c000066400000000000000000000723201501365277300152070ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef struct _CALLBACK_ARGS { YR_STRING* string; YR_SCAN_CONTEXT* context; const uint8_t* data; size_t data_size; uint64_t data_base; int forward_matches; int full_word; int xor_key; } CALLBACK_ARGS; static int _yr_scan_xor_compare( const uint8_t* data, size_t data_size, uint8_t* string, size_t string_length, uint8_t* xor_key) { int result = 0; const uint8_t* s1 = data; const uint8_t* s2 = string; uint8_t k = 0; size_t i = 0; if (data_size < string_length) goto _exit; // Calculate the xor key to compare with. *s1 is the start of the string we // matched on and *s2 is the "plaintext" string, so *s1 ^ *s2 is the key to // every *s2 as we compare. k = *s1 ^ *s2; while (i < string_length && *s1++ == ((*s2++) ^ k)) i++; result = (int) ((i == string_length) ? i : 0); _exit:; YR_DEBUG_FPRINTF( 2, stderr, "- %s(data_size=%zu string_length=%zu) {} = %d\n", __FUNCTION__, data_size, string_length, result); if (result > 0) *xor_key = k; return result; } static int _yr_scan_xor_wcompare( const uint8_t* data, size_t data_size, uint8_t* string, size_t string_length, uint8_t* xor_key) { int result = 0; const uint8_t* s1 = data; const uint8_t* s2 = string; uint8_t k = 0; size_t i = 0; if (data_size < string_length * 2) return 0; // Calculate the xor key to compare with. *s1 is the start of the string we // matched on and *s2 is the "plaintext" string, so *s1 ^ *s2 is the key to // every *s2 as we compare. k = *s1 ^ *s2; while (i < string_length && *s1 == ((*s2) ^ k) && ((*(s1 + 1)) ^ k) == 0x00) { s1 += 2; s2++; i++; } result = (int) ((i == string_length) ? i * 2 : 0); if (result > 0) *xor_key = k; return result; } static int _yr_scan_compare( const uint8_t* data, size_t data_size, uint8_t* string, size_t string_length) { const uint8_t* s1 = data; const uint8_t* s2 = string; size_t i = 0; if (data_size < string_length) return 0; while (i < string_length && *s1++ == *s2++) i++; return (int) ((i == string_length) ? i : 0); } static int _yr_scan_icompare( const uint8_t* data, size_t data_size, uint8_t* string, size_t string_length) { const uint8_t* s1 = data; const uint8_t* s2 = string; size_t i = 0; if (data_size < string_length) return 0; while (i < string_length && yr_lowercase[*s1++] == yr_lowercase[*s2++]) i++; return (int) ((i == string_length) ? i : 0); } static int _yr_scan_wcompare( const uint8_t* data, size_t data_size, uint8_t* string, size_t string_length) { int result = 0; const uint8_t* s1 = data; const uint8_t* s2 = string; size_t i = 0; if (data_size < string_length * 2) goto _exit; while (i < string_length && *s1 == *s2 && *(s1 + 1) == 0x00) { s1 += 2; s2++; i++; } result = (int) ((i == string_length) ? i * 2 : 0); _exit:; YR_DEBUG_FPRINTF( 2, stderr, "- %s(data_size=%zu string_length=%zu) {} = %d\n", __FUNCTION__, data_size, string_length, result); return result; } static int _yr_scan_wicompare( const uint8_t* data, size_t data_size, uint8_t* string, size_t string_length) { int result = 0; const uint8_t* s1 = data; const uint8_t* s2 = string; size_t i = 0; if (data_size < string_length * 2) goto _exit; while (i < string_length && yr_lowercase[*s1] == yr_lowercase[*s2] && *(s1 + 1) == 0x00) { s1 += 2; s2++; i++; } result = (int) ((i == string_length) ? i * 2 : 0); _exit:; YR_DEBUG_FPRINTF( 2, stderr, "- %s(data_size=%zu string_length=%zu) {} = %d\n", __FUNCTION__, data_size, string_length, result); return result; } static void _yr_scan_update_match_chain_length( YR_SCAN_CONTEXT* context, YR_STRING* string, YR_MATCH* match_to_update, int chain_length) { YR_MATCH* match; if (match_to_update->chain_length == chain_length) return; match_to_update->chain_length = chain_length; if (string->chained_to == NULL) return; match = context->unconfirmed_matches[string->chained_to->idx].head; while (match != NULL) { int64_t ending_offset = match->offset + match->match_length; if (ending_offset + string->chain_gap_max >= match_to_update->offset && ending_offset + string->chain_gap_min <= match_to_update->offset) { _yr_scan_update_match_chain_length( context, string->chained_to, match, chain_length + 1); } match = match->next; } } static int _yr_scan_add_match_to_list( YR_MATCH* match, YR_MATCHES* matches_list, int replace_if_exists) { int result = ERROR_SUCCESS; #if YR_DEBUG_VERBOSITY > 0 int32_t count_orig = matches_list->count; #endif YR_MATCH* insertion_point = matches_list->tail; if (matches_list->count == YR_MAX_STRING_MATCHES) { result = ERROR_TOO_MANY_MATCHES; goto _exit; } while (insertion_point != NULL) { if ((match->base + match->offset) == (insertion_point->base + insertion_point->offset)) { if (replace_if_exists) { insertion_point->match_length = match->match_length; insertion_point->data_length = match->data_length; insertion_point->data = match->data; } goto _exit; // return ERROR_SUCCESS } if ((match->base + match->offset) > (insertion_point->base + insertion_point->offset)) break; insertion_point = insertion_point->prev; } match->prev = insertion_point; if (insertion_point != NULL) { match->next = insertion_point->next; insertion_point->next = match; } else { match->next = matches_list->head; matches_list->head = match; } matches_list->count++; if (match->next != NULL) match->next->prev = match; else matches_list->tail = match; _exit:; YR_DEBUG_FPRINTF( 2, stderr, "- %s(replace_if_exists=%d) {} = %d //" " match->base=0x%" PRIx64 " match->offset=%" PRIi64 " matches_list->count=%u += %u\n", __FUNCTION__, replace_if_exists, result, match->base, match->offset, count_orig, matches_list->count - count_orig); return result; } static void _yr_scan_remove_match_from_list( YR_MATCH* match, YR_MATCHES* matches_list) { if (match->prev != NULL) match->prev->next = match->next; if (match->next != NULL) match->next->prev = match->prev; if (matches_list->head == match) matches_list->head = match->next; if (matches_list->tail == match) matches_list->tail = match->prev; matches_list->count--; match->next = NULL; match->prev = NULL; } // // _yr_scan_verify_chained_string_match // // Given a string that is part of a string chain and is matching at some // point in the scanned data, this function determines if the whole string // chain is also matching. For example, if the string S was splitted and // converted in a chain S1 <- S2 <- S3 (see yr_re_ast_split_at_chaining_point), // and a match for S3 was found, this functions finds out if there are matches // for S1 and S2 that together with the match found for S3 conform a match for // the whole S. // // Notice that this function operates in a non-greedy fashion. Matches found // for S will be the shortest possible ones. // static int _yr_scan_verify_chained_string_match( YR_STRING* matching_string, YR_SCAN_CONTEXT* context, const uint8_t* match_data, uint64_t match_base, uint64_t match_offset, int32_t match_length, uint8_t xor_key) { YR_DEBUG_FPRINTF( 2, stderr, "- %s (match_data=%p match_base=%" PRIx64 " match_offset=0x%" PRIx64 " match_length=%'d) {} \n", __FUNCTION__, match_data, match_base, match_offset, match_length); YR_STRING* string; YR_MATCH* match; YR_MATCH* next_match; YR_MATCH* new_match; uint64_t lowest_offset; uint64_t ending_offset; int32_t full_chain_length; bool add_match = false; if (matching_string->chained_to == NULL) { // The matching string is the head of the chain, this match should be // added to the list of unconfirmed matches. The match will remain // unconfirmed until all the strings in the chain are found with the // correct distances between them. add_match = true; } else { // If some unconfirmed match exists, the lowest possible offset where the // whole string chain can match is the offset of the first string in the // list of unconfirmed matches. Unconfirmed matches are sorted in ascending // offset order. If no unconfirmed match exists, the lowest possible offset // is the offset of the current match. match = context->unconfirmed_matches[matching_string->idx].head; if (match != NULL) lowest_offset = match->offset; else lowest_offset = match_offset; // Iterate over the list of unconfirmed matches for the string that // precedes the currently matching string. If we have a string chain like: // S1 <- S2 <- S3, and we just found a match for S2, we are iterating the // list of unconfirmed matches of S1. match = context->unconfirmed_matches[matching_string->chained_to->idx].head; while (match != NULL) { // Store match->next so that we can use it later for advancing in the // list, if _yr_scan_remove_match_from_list is called, match->next is // set to NULL, that's why we store its current value before that happens. next_match = match->next; // The unconfirmed match starts at match->offset and finishes at // ending_offset. ending_offset = match->offset + match->match_length; if (ending_offset + matching_string->chain_gap_max < lowest_offset) { // If the current match is too far away from the unconfirmed match, // remove the unconfirmed match from the list because it has been // negatively confirmed (i.e: we can be sure that this unconfirmed // match can't be an actual match) _yr_scan_remove_match_from_list( match, &context->unconfirmed_matches[matching_string->chained_to->idx]); } else if ( ending_offset + matching_string->chain_gap_max >= match_offset && ending_offset + matching_string->chain_gap_min <= match_offset) { // If the distance between the end of the unconfirmed match and the // start of the current match is within the range specified in the // regexp or hex string, this could be an actual match. add_match = true; break; } match = next_match; } } if (add_match) { uint32_t max_match_data; FAIL_ON_ERROR( yr_get_configuration_uint32(YR_CONFIG_MAX_MATCH_DATA, &max_match_data)) if (STRING_IS_CHAIN_TAIL(matching_string)) { // The matching string is the tail of the string chain. It must be // chained to some other string. assert(matching_string->chained_to != NULL); // Iterate over the list of unconfirmed matches of the preceding string // in the chain and update the chain_length field for each of them. This // is a recursive operation that will update the chain_length field for // every unconfirmed match in all the strings in the chain up to the head // of the chain. match = context->unconfirmed_matches[matching_string->chained_to->idx].head; while (match != NULL) { ending_offset = match->offset + match->match_length; if (ending_offset + matching_string->chain_gap_max >= match_offset && ending_offset + matching_string->chain_gap_min <= match_offset) { _yr_scan_update_match_chain_length( context, matching_string->chained_to, match, 1); } match = match->next; } full_chain_length = 0; string = matching_string; while (string->chained_to != NULL) { full_chain_length++; string = string->chained_to; } // "string" points now to the head of the strings chain. match = context->unconfirmed_matches[string->idx].head; // Iterate over the list of unconfirmed matches of the head of the chain, // and move to the list of confirmed matches those with a chain_length // equal to full_chain_length, which means that the whole chain has been // confirmed to match. while (match != NULL) { next_match = match->next; if (match->chain_length == full_chain_length) { _yr_scan_remove_match_from_list( match, &context->unconfirmed_matches[string->idx]); match->match_length = (int32_t) (match_offset - match->offset + match_length); match->data_length = yr_min( match->match_length, (int32_t) max_match_data); match->data = yr_notebook_alloc( context->matches_notebook, match->data_length); if (match->data == NULL) return ERROR_INSUFFICIENT_MEMORY; memcpy( (void*) match->data, match_data - match_offset + match->offset, match->data_length); // Once a string is found, the rule containing that string is // required to be evaluated. yr_bitmask_set(context->required_eval, string->rule_idx); FAIL_ON_ERROR(_yr_scan_add_match_to_list( match, &context->matches[string->idx], false)); } match = next_match; } } else // It's a part of a chain, but not the tail. { new_match = yr_notebook_alloc( context->matches_notebook, sizeof(YR_MATCH)); if (new_match == NULL) return ERROR_INSUFFICIENT_MEMORY; new_match->base = match_base; new_match->offset = match_offset; new_match->match_length = match_length; new_match->chain_length = 0; new_match->prev = NULL; new_match->next = NULL; new_match->is_private = STRING_IS_PRIVATE(matching_string); new_match->xor_key = xor_key; // A copy of the matching data is written to the matches_arena, the // amount of data copies is limited by YR_CONFIG_MAX_MATCH_DATA. new_match->data_length = yr_min(match_length, (int32_t) max_match_data); if (new_match->data_length > 0) { new_match->data = yr_notebook_alloc( context->matches_notebook, new_match->data_length); if (new_match->data == NULL) return ERROR_INSUFFICIENT_MEMORY; memcpy((void*) new_match->data, match_data, new_match->data_length); } else { new_match->data = NULL; } // Add the match to the list of unconfirmed matches because the string // is part of a chain but not its tail, so we can't be sure the this is // an actual match until finding the remaining parts of the chain. FAIL_ON_ERROR(_yr_scan_add_match_to_list( new_match, &context->unconfirmed_matches[matching_string->idx], false)); } } return ERROR_SUCCESS; } static int _yr_scan_match_callback( const uint8_t* match_data, int32_t match_length, int flags, void* args) { CALLBACK_ARGS* callback_args = (CALLBACK_ARGS*) args; YR_STRING* string = callback_args->string; YR_MATCH* new_match; int result = ERROR_SUCCESS; size_t match_offset = match_data - callback_args->data; YR_DEBUG_FPRINTF( 2, stderr, "+ %s(match_data=%p match_length=%d) { //" " match_offset=%zu args->data=%p args->string.length=%u" " args->data_base=0x%" PRIx64 " args->data_size=%zu" " args->forward_matches=%'u\n", __FUNCTION__, match_data, match_length, match_offset, callback_args->data, callback_args->string->length, callback_args->data_base, callback_args->data_size, callback_args->forward_matches); // total match length is the sum of backward and forward matches. match_length += callback_args->forward_matches; // make sure that match fits into the data. assert(match_offset + match_length <= callback_args->data_size); if (callback_args->full_word) { if (flags & RE_FLAGS_WIDE) { if (match_offset >= 2 && *(match_data - 1) == 0 && yr_isalnum(match_data - 2)) goto _exit; // return ERROR_SUCCESS; if (match_offset + match_length + 1 < callback_args->data_size && *(match_data + match_length + 1) == 0 && yr_isalnum(match_data + match_length)) goto _exit; // return ERROR_SUCCESS; } else { if (match_offset >= 1 && yr_isalnum(match_data - 1)) goto _exit; // return ERROR_SUCCESS; if (match_offset + match_length < callback_args->data_size && yr_isalnum(match_data + match_length)) goto _exit; // return ERROR_SUCCESS; } } if (STRING_IS_CHAIN_PART(string)) { result = _yr_scan_verify_chained_string_match( string, callback_args->context, match_data, callback_args->data_base, match_offset, match_length, callback_args->xor_key); } else { uint32_t max_match_data; FAIL_ON_ERROR( yr_get_configuration_uint32(YR_CONFIG_MAX_MATCH_DATA, &max_match_data)); new_match = yr_notebook_alloc( callback_args->context->matches_notebook, sizeof(YR_MATCH)); if (new_match == NULL) { result = ERROR_INSUFFICIENT_MEMORY; goto _exit; } new_match->data_length = yr_min(match_length, (int32_t) max_match_data); if (new_match->data_length > 0) { new_match->data = yr_notebook_alloc( callback_args->context->matches_notebook, new_match->data_length); if (new_match->data == NULL) { result = ERROR_INSUFFICIENT_MEMORY; goto _exit; } memcpy((void*) new_match->data, match_data, new_match->data_length); } else { new_match->data = NULL; } if (result == ERROR_SUCCESS) { new_match->base = callback_args->data_base; new_match->offset = match_offset; new_match->match_length = match_length; new_match->prev = NULL; new_match->next = NULL; new_match->is_private = STRING_IS_PRIVATE(string); new_match->xor_key = callback_args->xor_key; yr_bitmask_set(callback_args->context->required_eval, string->rule_idx); FAIL_ON_ERROR(_yr_scan_add_match_to_list( new_match, &callback_args->context->matches[string->idx], STRING_IS_GREEDY_REGEXP(string))); } } _exit:; YR_DEBUG_FPRINTF(2, stderr, "} = %d // %s()\n", result, __FUNCTION__); return result; } typedef int (*RE_EXEC_FUNC)( YR_SCAN_CONTEXT* context, const uint8_t* code, const uint8_t* input, size_t input_forwards_size, size_t input_backwards_size, int flags, RE_MATCH_CALLBACK_FUNC callback, void* callback_args, int* matches); static int _yr_scan_verify_re_match( YR_SCAN_CONTEXT* context, YR_AC_MATCH* ac_match, const uint8_t* data, size_t data_size, uint64_t data_base, size_t offset) { YR_DEBUG_FPRINTF( 2, stderr, "- %s(data=%p data_size=%zu data_base=0x%" PRIx64 " offset=%zu) {}\n", __FUNCTION__, data, data_size, data_base, offset); CALLBACK_ARGS callback_args; RE_EXEC_FUNC exec; int flags = 0; if (STRING_IS_GREEDY_REGEXP(ac_match->string)) flags |= RE_FLAGS_GREEDY; if (STRING_IS_NO_CASE(ac_match->string)) flags |= RE_FLAGS_NO_CASE; if (STRING_IS_DOT_ALL(ac_match->string)) flags |= RE_FLAGS_DOT_ALL; if (STRING_IS_FAST_REGEXP(ac_match->string)) exec = yr_re_fast_exec; else exec = yr_re_exec; callback_args.string = ac_match->string; callback_args.context = context; callback_args.data = data; callback_args.data_size = data_size; callback_args.data_base = data_base; callback_args.forward_matches = -1; callback_args.full_word = STRING_IS_FULL_WORD(ac_match->string); // xor modifier is not valid for RE but set it so we don't leak stack values. callback_args.xor_key = 0; if (STRING_IS_ASCII(ac_match->string) || // The base64 and base64wide are not supported in regexps, but strings // with these modifiers are converted to a regexp with three // alternatives. STRING_IS_BASE64(ac_match->string) || STRING_IS_BASE64_WIDE(ac_match->string)) { FAIL_ON_ERROR(exec( context, ac_match->forward_code, data + offset, data_size - offset, offset, flags, NULL, NULL, &callback_args.forward_matches)); if (callback_args.forward_matches != -1 && ac_match->backward_code != NULL) { FAIL_ON_ERROR(exec( context, ac_match->backward_code, data + offset, data_size - offset, offset, flags | RE_FLAGS_BACKWARDS | RE_FLAGS_EXHAUSTIVE, _yr_scan_match_callback, (void*) &callback_args, NULL)); } else if (callback_args.forward_matches >= 0) { FAIL_ON_ERROR( _yr_scan_match_callback(data + offset, 0, flags, &callback_args)); } } if (STRING_IS_WIDE(ac_match->string)) { FAIL_ON_ERROR(exec( context, ac_match->forward_code, data + offset, data_size - offset, offset, flags | RE_FLAGS_WIDE, NULL, NULL, &callback_args.forward_matches)); if (callback_args.forward_matches != -1 && ac_match->backward_code != NULL) { FAIL_ON_ERROR(exec( context, ac_match->backward_code, data + offset, data_size - offset, offset, flags | RE_FLAGS_WIDE | RE_FLAGS_BACKWARDS | RE_FLAGS_EXHAUSTIVE, _yr_scan_match_callback, (void*) &callback_args, NULL)); } else if (callback_args.forward_matches >= 0) { FAIL_ON_ERROR( _yr_scan_match_callback(data + offset, 0, flags, &callback_args)); } } return ERROR_SUCCESS; } static int _yr_scan_verify_literal_match( YR_SCAN_CONTEXT* context, YR_AC_MATCH* ac_match, const uint8_t* data, size_t data_size, uint64_t data_base, size_t offset) { YR_DEBUG_FPRINTF( 2, stderr, "- %s(data=%p data_size=%zu data_base=0x%" PRIx64 " offset=%zu) {}\n", __FUNCTION__, data, data_size, data_base, offset); int flags = 0; int forward_matches = 0; uint8_t xor_key = 0; CALLBACK_ARGS callback_args; YR_STRING* string = ac_match->string; if (STRING_FITS_IN_ATOM(string)) { forward_matches = ac_match->backtrack; if (STRING_IS_XOR(string)) { if (STRING_IS_WIDE(string)) { _yr_scan_xor_wcompare( data + offset, data_size - offset, string->string, string->length, &xor_key); } if (STRING_IS_ASCII(string)) { _yr_scan_xor_compare( data + offset, data_size - offset, string->string, string->length, &xor_key); } } } else if (STRING_IS_NO_CASE(string)) { if (STRING_IS_ASCII(string)) { forward_matches = _yr_scan_icompare( data + offset, data_size - offset, string->string, string->length); } if (STRING_IS_WIDE(string) && forward_matches == 0) { forward_matches = _yr_scan_wicompare( data + offset, data_size - offset, string->string, string->length); } } else { if (STRING_IS_ASCII(string)) { forward_matches = _yr_scan_compare( data + offset, data_size - offset, string->string, string->length); } if (STRING_IS_WIDE(string) && forward_matches == 0) { forward_matches = _yr_scan_wcompare( data + offset, data_size - offset, string->string, string->length); } if (STRING_IS_XOR(string) && forward_matches == 0) { if (STRING_IS_WIDE(string)) { forward_matches = _yr_scan_xor_wcompare( data + offset, data_size - offset, string->string, string->length, &xor_key); } if (forward_matches == 0) { forward_matches = _yr_scan_xor_compare( data + offset, data_size - offset, string->string, string->length, &xor_key); } } } if (forward_matches == 0) return ERROR_SUCCESS; if (forward_matches == string->length * 2) flags |= RE_FLAGS_WIDE; if (STRING_IS_NO_CASE(string)) flags |= RE_FLAGS_NO_CASE; callback_args.context = context; callback_args.string = string; callback_args.data = data; callback_args.data_size = data_size; callback_args.data_base = data_base; callback_args.forward_matches = forward_matches; callback_args.full_word = STRING_IS_FULL_WORD(string); callback_args.xor_key = xor_key; FAIL_ON_ERROR( _yr_scan_match_callback(data + offset, 0, flags, &callback_args)); return ERROR_SUCCESS; } int yr_scan_verify_match( YR_SCAN_CONTEXT* context, YR_AC_MATCH* ac_match, const uint8_t* data, size_t data_size, uint64_t data_base, size_t offset) { YR_DEBUG_FPRINTF( 2, stderr, "- %s(data=%p data_size=%zu data_base=0x%" PRIx64 " offset=%zu) {}\n", __FUNCTION__, data, data_size, data_base, offset); YR_STRING* string = ac_match->string; YR_CALLBACK_FUNC callback = context->callback; int result; if (data_size - offset <= 0) return ERROR_SUCCESS; if (yr_bitmask_is_set(context->strings_temp_disabled, string->idx)) return ERROR_SUCCESS; if (context->flags & SCAN_FLAGS_FAST_MODE && STRING_IS_SINGLE_MATCH(string) && context->matches[string->idx].head != NULL) return ERROR_SUCCESS; if (STRING_IS_FIXED_OFFSET(string) && string->fixed_offset != data_base + offset) return ERROR_SUCCESS; #ifdef YR_PROFILING_ENABLED uint64_t start_time; bool sample = context->profiling_info[string->rule_idx].atom_matches % YR_MATCH_VERIFICATION_PROFILING_RATE == 0; if (sample) start_time = yr_stopwatch_elapsed_ns(&context->stopwatch); #endif if (STRING_IS_LITERAL(string)) { result = _yr_scan_verify_literal_match( context, ac_match, data, data_size, data_base, offset); } else { result = _yr_scan_verify_re_match( context, ac_match, data, data_size, data_base, offset); } // If _yr_scan_verify_literal_match or _yr_scan_verify_re_match return // ERROR_TOO_MANY_MATCHES call the callback with CALLBACK_MSG_TOO_MANY_MATCHES // in order to ask what to do. If the callback returns CALLBACK_CONTINUE // this error is ignored, if not, the error is propagated to the caller. if (result == ERROR_TOO_MANY_MATCHES) { result = callback( context, CALLBACK_MSG_TOO_MANY_MATCHES, (void*) string, context->user_data); switch (result) { case CALLBACK_CONTINUE: yr_bitmask_set(context->strings_temp_disabled, string->idx); result = ERROR_SUCCESS; break; default: result = ERROR_TOO_MANY_MATCHES; break; } } #ifdef YR_PROFILING_ENABLED if (sample) { uint64_t finish_time = yr_stopwatch_elapsed_ns(&context->stopwatch); context->profiling_info[string->rule_idx].match_time += (finish_time - start_time); } context->profiling_info[string->rule_idx].atom_matches++; #endif if (result != ERROR_SUCCESS) context->last_error_string = string; return result; } yara-4.5.3/libyara/scanner.c000066400000000000000000000575301501365277300157220ustar00rootroot00000000000000/* Copyright (c) 2018. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "exception.h" static int _yr_scanner_scan_mem_block( YR_SCANNER* scanner, const uint8_t* block_data, YR_MEMORY_BLOCK* block) { YR_DEBUG_FPRINTF( 2, stderr, "+ %s(block_data=%p block->base=0x%" PRIx64 " block->size=%zu) {\n", __FUNCTION__, block_data, block->base, block->size); int result = ERROR_SUCCESS; YR_RULES* rules = scanner->rules; YR_AC_TRANSITION* transition_table = rules->ac_transition_table; uint32_t* match_table = rules->ac_match_table; YR_AC_MATCH* match; YR_AC_TRANSITION transition; size_t i = 0; uint32_t state = YR_AC_ROOT_STATE; uint16_t index; YR_STRING* report_string = NULL; YR_RULE* rule = NULL; while (i < block->size) { if (i % 4096 == 0 && scanner->timeout > 0) { if (yr_stopwatch_elapsed_ns(&scanner->stopwatch) > scanner->timeout) { result = ERROR_SCAN_TIMEOUT; goto _exit; } } #if 2 == YR_DEBUG_VERBOSITY if (0 != state) YR_DEBUG_FPRINTF( 2, stderr, "- match_table[state=%u]=%'u i=%'ld " "block_data=%p block->base=0x%" PRIx64 " // %s()\n", state, match_table[state], i, block_data, block->base, __FUNCTION__); #endif if (match_table[state] != 0) { // If the entry corresponding to state N in the match table is zero, it // means that there's no match associated to the state. If it's non-zero, // its value is the 1-based index within ac_match_pool where the first // match resides. match = &rules->ac_match_pool[match_table[state] - 1]; if (scanner->matches->count >= YR_SLOW_STRING_MATCHES) { report_string = match->string; rule = report_string ? &scanner->rules->rules_table[report_string->rule_idx] : NULL; } while (match != NULL) { if (match->backtrack <= i) { GOTO_EXIT_ON_ERROR(yr_scan_verify_match( scanner, match, block_data, block->size, block->base, i - match->backtrack)); } match = match->next; } } index = block_data[i++] + 1; transition = transition_table[state + index]; while (YR_AC_INVALID_TRANSITION(transition, index)) { if (state != YR_AC_ROOT_STATE) { state = YR_AC_NEXT_STATE(transition_table[state]); transition = transition_table[state + index]; } else { transition = 0; break; } } state = YR_AC_NEXT_STATE(transition); } if (match_table[state] != 0) { match = &rules->ac_match_pool[match_table[state] - 1]; while (match != NULL) { if (match->backtrack <= i) { GOTO_EXIT_ON_ERROR(yr_scan_verify_match( scanner, match, block_data, block->size, block->base, i - match->backtrack)); } match = match->next; } } if (rule != NULL && scanner->matches->count >= YR_SLOW_STRING_MATCHES && scanner->matches->count < YR_MAX_STRING_MATCHES) { if (rule != NULL && report_string != NULL) { result = scanner->callback( scanner, CALLBACK_MSG_TOO_SLOW_SCANNING, (void*) report_string, scanner->user_data); if (result != CALLBACK_CONTINUE) { result = ERROR_TOO_SLOW_SCANNING; goto _exit; } } } _exit: YR_DEBUG_FPRINTF( 2, stderr, "} = %d AKA %s // %s()\n", result, yr_debug_error_as_string(result), __FUNCTION__); return result; } static void _yr_scanner_clean_matches(YR_SCANNER* scanner) { YR_DEBUG_FPRINTF(2, stderr, "- %s() {} \n", __FUNCTION__); memset( scanner->rule_matches_flags, 0, sizeof(YR_BITMASK) * YR_BITMASK_SIZE(scanner->rules->num_rules)); memset( scanner->required_eval, 0, sizeof(YR_BITMASK) * YR_BITMASK_SIZE(scanner->rules->num_rules)); memset( scanner->ns_unsatisfied_flags, 0, sizeof(YR_BITMASK) * YR_BITMASK_SIZE(scanner->rules->num_namespaces)); memset( scanner->strings_temp_disabled, 0, sizeof(YR_BITMASK) * YR_BITMASK_SIZE(scanner->rules->num_strings)); memset(scanner->matches, 0, sizeof(YR_MATCHES) * scanner->rules->num_strings); memset( scanner->unconfirmed_matches, 0, sizeof(YR_MATCHES) * scanner->rules->num_strings); } YR_API int yr_scanner_create(YR_RULES* rules, YR_SCANNER** scanner) { YR_DEBUG_FPRINTF(2, stderr, "- %s() {} \n", __FUNCTION__); YR_EXTERNAL_VARIABLE* external; YR_SCANNER* new_scanner; new_scanner = (YR_SCANNER*) yr_calloc(1, sizeof(YR_SCANNER)); if (new_scanner == NULL) return ERROR_INSUFFICIENT_MEMORY; FAIL_ON_ERROR_WITH_CLEANUP( yr_hash_table_create(64, &new_scanner->objects_table), yr_free(new_scanner)); new_scanner->rules = rules; new_scanner->entry_point = YR_UNDEFINED; new_scanner->file_size = YR_UNDEFINED; new_scanner->canary = rand(); // By default report both matching and non-matching rules. new_scanner->flags = SCAN_FLAGS_REPORT_RULES_MATCHING | SCAN_FLAGS_REPORT_RULES_NOT_MATCHING; new_scanner->rule_matches_flags = (YR_BITMASK*) yr_calloc( sizeof(YR_BITMASK), YR_BITMASK_SIZE(rules->num_rules)); new_scanner->required_eval = (YR_BITMASK*) yr_calloc( sizeof(YR_BITMASK), YR_BITMASK_SIZE(rules->num_rules)); new_scanner->ns_unsatisfied_flags = (YR_BITMASK*) yr_calloc( sizeof(YR_BITMASK), YR_BITMASK_SIZE(rules->num_namespaces)); new_scanner->strings_temp_disabled = (YR_BITMASK*) yr_calloc( sizeof(YR_BITMASK), YR_BITMASK_SIZE(rules->num_strings)); new_scanner->matches = (YR_MATCHES*) yr_calloc( rules->num_strings, sizeof(YR_MATCHES)); new_scanner->unconfirmed_matches = (YR_MATCHES*) yr_calloc( rules->num_strings, sizeof(YR_MATCHES)); if (new_scanner->rule_matches_flags == NULL || new_scanner->required_eval == NULL || new_scanner->ns_unsatisfied_flags == NULL || new_scanner->strings_temp_disabled == NULL || (new_scanner->matches == NULL && rules->num_strings > 0) || (new_scanner->unconfirmed_matches == NULL && rules->num_strings > 0)) { yr_scanner_destroy(new_scanner); return ERROR_INSUFFICIENT_MEMORY; } #ifdef YR_PROFILING_ENABLED new_scanner->profiling_info = yr_calloc( rules->num_rules, sizeof(YR_PROFILING_INFO)); if (new_scanner->profiling_info == NULL && rules->num_rules > 0) { yr_scanner_destroy(new_scanner); return ERROR_INSUFFICIENT_MEMORY; } #else new_scanner->profiling_info = NULL; #endif external = rules->ext_vars_table; while (!EXTERNAL_VARIABLE_IS_NULL(external)) { YR_OBJECT* object; FAIL_ON_ERROR_WITH_CLEANUP( yr_object_from_external_variable(external, &object), // cleanup yr_scanner_destroy(new_scanner)); FAIL_ON_ERROR_WITH_CLEANUP(yr_hash_table_add( new_scanner->objects_table, external->identifier, NULL, (void*) object), // cleanup yr_object_destroy(object); yr_scanner_destroy(new_scanner)); yr_object_set_canary(object, new_scanner->canary); external++; } *scanner = new_scanner; return ERROR_SUCCESS; } YR_API void yr_scanner_destroy(YR_SCANNER* scanner) { YR_DEBUG_FPRINTF(2, stderr, "- %s() {} \n", __FUNCTION__); RE_FIBER* fiber = scanner->re_fiber_pool.fibers.head; while (fiber != NULL) { RE_FIBER* next = fiber->next; yr_free(fiber); fiber = next; } RE_FAST_EXEC_POSITION* position = scanner->re_fast_exec_position_pool.head; while (position != NULL) { RE_FAST_EXEC_POSITION* next = position->next; yr_free(position); position = next; } if (scanner->objects_table != NULL) { yr_hash_table_destroy( scanner->objects_table, (YR_HASH_TABLE_FREE_VALUE_FUNC) yr_object_destroy); } #ifdef YR_PROFILING_ENABLED yr_free(scanner->profiling_info); #endif yr_free(scanner->rule_matches_flags); yr_free(scanner->ns_unsatisfied_flags); yr_free(scanner->required_eval); yr_free(scanner->strings_temp_disabled); yr_free(scanner->matches); yr_free(scanner->unconfirmed_matches); yr_free(scanner); } YR_API void yr_scanner_set_callback( YR_SCANNER* scanner, YR_CALLBACK_FUNC callback, void* user_data) { scanner->callback = callback; scanner->user_data = user_data; } YR_API void yr_scanner_set_timeout(YR_SCANNER* scanner, int timeout) { // Convert timeout from seconds to nanoseconds. scanner->timeout = timeout * 1000000000ULL; } YR_API void yr_scanner_set_flags(YR_SCANNER* scanner, int flags) { // For backward compatibility, if neither SCAN_FLAGS_REPORT_RULES_MATCHING // nor SCAN_FLAGS_REPORT_RULES_NOT_MATCHING are specified, both are assumed. if (!(flags & SCAN_FLAGS_REPORT_RULES_MATCHING) && !(flags & SCAN_FLAGS_REPORT_RULES_NOT_MATCHING)) { flags |= SCAN_FLAGS_REPORT_RULES_MATCHING | SCAN_FLAGS_REPORT_RULES_NOT_MATCHING; } scanner->flags = flags; } YR_API int yr_scanner_define_integer_variable( YR_SCANNER* scanner, const char* identifier, int64_t value) { YR_OBJECT* obj = (YR_OBJECT*) yr_hash_table_lookup( scanner->objects_table, identifier, NULL); if (obj == NULL) return ERROR_INVALID_ARGUMENT; if (obj->type != OBJECT_TYPE_INTEGER) return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE; return yr_object_set_integer(value, obj, NULL); } YR_API int yr_scanner_define_boolean_variable( YR_SCANNER* scanner, const char* identifier, int value) { return yr_scanner_define_integer_variable(scanner, identifier, value); } YR_API int yr_scanner_define_float_variable( YR_SCANNER* scanner, const char* identifier, double value) { YR_OBJECT* obj = (YR_OBJECT*) yr_hash_table_lookup( scanner->objects_table, identifier, NULL); if (obj == NULL) return ERROR_INVALID_ARGUMENT; if (obj->type != OBJECT_TYPE_FLOAT) return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE; return yr_object_set_float(value, obj, NULL); } YR_API int yr_scanner_define_string_variable( YR_SCANNER* scanner, const char* identifier, const char* value) { YR_OBJECT* obj = (YR_OBJECT*) yr_hash_table_lookup( scanner->objects_table, identifier, NULL); if (obj == NULL) return ERROR_INVALID_ARGUMENT; if (obj->type != OBJECT_TYPE_STRING) return ERROR_INVALID_EXTERNAL_VARIABLE_TYPE; return yr_object_set_string(value, strlen(value), obj, NULL); } YR_API int yr_scanner_scan_mem_blocks( YR_SCANNER* scanner, YR_MEMORY_BLOCK_ITERATOR* iterator) { YR_DEBUG_FPRINTF(2, stderr, "+ %s() {\n", __FUNCTION__); YR_RULES* rules; YR_RULE* rule; YR_MEMORY_BLOCK* block; int i, result = ERROR_SUCCESS; if (scanner->callback == NULL) { result = ERROR_CALLBACK_REQUIRED; goto _exit; } scanner->iterator = iterator; rules = scanner->rules; if (iterator->last_error == ERROR_BLOCK_NOT_READY) { // The caller is invoking yr_scanner_scan_mem_blocks again because the // previous call returned ERROR_BLOCK_NOT_READY. block = iterator->next(iterator); } else { // Create the notebook that will hold the YR_MATCH structures representing // each match found. This notebook will also contain snippets of the // matching data (the "data" field in YR_MATCH points to the snippet // corresponding to the match). Each notebook's page can store up to 1024 // matches. uint32_t max_match_data; FAIL_ON_ERROR( yr_get_configuration_uint32(YR_CONFIG_MAX_MATCH_DATA, &max_match_data)); result = yr_notebook_create( 1024 * (sizeof(YR_MATCH) + max_match_data), &scanner->matches_notebook); if (result != ERROR_SUCCESS) goto _exit; // Every rule that doesn't require a matching string must be evaluated // regardless of whether a string matched or not. memcpy( scanner->required_eval, scanner->rules->no_required_strings, sizeof(YR_BITMASK) * YR_BITMASK_SIZE(rules->num_rules)); yr_stopwatch_start(&scanner->stopwatch); block = iterator->first(iterator); } YR_TRYCATCH( !(scanner->flags & SCAN_FLAGS_NO_TRYCATCH), { while (block != NULL) { const uint8_t* data = yr_fetch_block_data(block); // fetch_data may fail and return NULL. if (data == NULL) { block = iterator->next(iterator); continue; } if (scanner->entry_point == YR_UNDEFINED) { if (scanner->flags & SCAN_FLAGS_PROCESS_MEMORY) scanner->entry_point = yr_get_entry_point_address( data, block->size, block->base); else scanner->entry_point = yr_get_entry_point_offset( data, block->size); } result = _yr_scanner_scan_mem_block(scanner, data, block); if (result != ERROR_SUCCESS) { break; } block = iterator->next(iterator); } }, { result = ERROR_COULD_NOT_MAP_FILE; }); if (result != ERROR_SUCCESS) goto _exit; result = iterator->last_error; if (result != ERROR_SUCCESS) goto _exit; // If the iterator has a file_size function, ask the function for the file's // size, if not file size is undefined. if (iterator->file_size != NULL) scanner->file_size = iterator->file_size(iterator); else scanner->file_size = YR_UNDEFINED; YR_TRYCATCH( !(scanner->flags & SCAN_FLAGS_NO_TRYCATCH), { result = yr_execute_code(scanner); }, { result = ERROR_COULD_NOT_MAP_FILE; }); if (result != ERROR_SUCCESS) goto _exit; for (i = 0, rule = rules->rules_table; !RULE_IS_NULL(rule); i++, rule++) { int message = 0; if (yr_bitmask_is_set(scanner->rule_matches_flags, i) && yr_bitmask_is_not_set(scanner->ns_unsatisfied_flags, rule->ns->idx)) { if (scanner->flags & SCAN_FLAGS_REPORT_RULES_MATCHING) message = CALLBACK_MSG_RULE_MATCHING; } else { if (scanner->flags & SCAN_FLAGS_REPORT_RULES_NOT_MATCHING) message = CALLBACK_MSG_RULE_NOT_MATCHING; } if (message != 0 && !RULE_IS_PRIVATE(rule)) { switch (scanner->callback(scanner, message, rule, scanner->user_data)) { case CALLBACK_ABORT: result = ERROR_SUCCESS; goto _exit; case CALLBACK_ERROR: result = ERROR_CALLBACK_ERROR; goto _exit; } } } scanner->callback( scanner, CALLBACK_MSG_SCAN_FINISHED, NULL, scanner->user_data); _exit: // If error is ERROR_BLOCK_NOT_READY we don't clean the matches and don't // destroy the notebook yet. ERROR_BLOCK_NOT_READY is not a permament error, // the caller can still call this function again for a retry. if (result != ERROR_BLOCK_NOT_READY) { _yr_scanner_clean_matches(scanner); if (scanner->matches_notebook != NULL) { yr_notebook_destroy(scanner->matches_notebook); scanner->matches_notebook = NULL; } } YR_DEBUG_FPRINTF( 2, stderr, "} = %d AKA %s // %s()\n", result, yr_debug_error_as_string(result), __FUNCTION__); return result; } static YR_MEMORY_BLOCK* _yr_get_first_block(YR_MEMORY_BLOCK_ITERATOR* iterator) { YR_MEMORY_BLOCK* result = (YR_MEMORY_BLOCK*) iterator->context; YR_DEBUG_FPRINTF( 2, stderr, "- %s() {} = %p // default iterator; single memory block, blocking\n", __FUNCTION__, result); return result; } static YR_MEMORY_BLOCK* _yr_get_next_block(YR_MEMORY_BLOCK_ITERATOR* iterator) { YR_MEMORY_BLOCK* result = NULL; YR_DEBUG_FPRINTF( 2, stderr, "- %s() {} = %p // default iterator; single memory block, blocking\n", __FUNCTION__, result); return result; } static uint64_t _yr_get_file_size(YR_MEMORY_BLOCK_ITERATOR* iterator) { uint64_t file_size = ((YR_MEMORY_BLOCK*) iterator->context)->size; YR_DEBUG_FPRINTF( 2, stderr, "- %s() {} = %" PRIu64 " // default iterator; single memory block, blocking\n", __FUNCTION__, file_size); return file_size; } static const uint8_t* _yr_fetch_block_data(YR_MEMORY_BLOCK* block) { return (const uint8_t*) block->context; } YR_API const uint8_t* yr_fetch_block_data(YR_MEMORY_BLOCK* block) { const uint8_t* data = block->fetch_data(block); if (data == NULL) { return NULL; } jumpinfo* info = (jumpinfo*) yr_thread_storage_get_value( &yr_trycatch_trampoline_tls); if (info == NULL) // Not called from YR_TRYCATCH { return data; } info->memfault_from = (void*) data; info->memfault_to = (void*) (data + block->size); return data; } YR_API int yr_scanner_scan_mem( YR_SCANNER* scanner, const uint8_t* buffer, size_t buffer_size) { YR_DEBUG_FPRINTF( 2, stderr, "+ %s(buffer=%p buffer_size=%zu) {\n", __FUNCTION__, buffer, buffer_size); YR_MEMORY_BLOCK block; YR_MEMORY_BLOCK_ITERATOR iterator; int result; block.size = buffer_size; block.base = 0; block.fetch_data = _yr_fetch_block_data; block.context = (void*) buffer; iterator.context = █ iterator.first = _yr_get_first_block; iterator.next = _yr_get_next_block; iterator.file_size = _yr_get_file_size; iterator.last_error = ERROR_SUCCESS; // Detect cases where every byte of input is checked for match and input size // is bigger then 0.2 MB if (scanner->rules->ac_match_table[YR_AC_ROOT_STATE] != 0 && buffer_size > YR_FILE_SIZE_THRESHOLD) { YR_STRING* report_string = scanner->rules->ac_match_pool[YR_AC_ROOT_STATE].string; result = scanner->callback( scanner, CALLBACK_MSG_TOO_SLOW_SCANNING, (void*) report_string, scanner->user_data); if (result != CALLBACK_CONTINUE) return ERROR_TOO_SLOW_SCANNING; } result = yr_scanner_scan_mem_blocks(scanner, &iterator); YR_DEBUG_FPRINTF( 2, stderr, "} = %d AKA %s // %s()\n", result, yr_debug_error_as_string(result), __FUNCTION__); return result; } YR_API int yr_scanner_scan_file(YR_SCANNER* scanner, const char* filename) { YR_MAPPED_FILE mfile; int result = yr_filemap_map(filename, &mfile); if (result == ERROR_SUCCESS) { result = yr_scanner_scan_mem(scanner, mfile.data, mfile.size); yr_filemap_unmap(&mfile); } return result; } YR_API int yr_scanner_scan_fd(YR_SCANNER* scanner, YR_FILE_DESCRIPTOR fd) { YR_MAPPED_FILE mfile; int result = yr_filemap_map_fd(fd, 0, 0, &mfile); if (result == ERROR_SUCCESS) { result = yr_scanner_scan_mem(scanner, mfile.data, mfile.size); yr_filemap_unmap_fd(&mfile); } return result; } YR_API int yr_scanner_scan_proc(YR_SCANNER* scanner, int pid) { YR_MEMORY_BLOCK_ITERATOR iterator; int result = yr_process_open_iterator(pid, &iterator); if (result == ERROR_SUCCESS) { int prev_flags = scanner->flags; scanner->flags |= SCAN_FLAGS_PROCESS_MEMORY; result = yr_scanner_scan_mem_blocks(scanner, &iterator); scanner->flags = prev_flags; yr_process_close_iterator(&iterator); } return result; } YR_API YR_STRING* yr_scanner_last_error_string(YR_SCANNER* scanner) { return scanner->last_error_string; } YR_API YR_RULE* yr_scanner_last_error_rule(YR_SCANNER* scanner) { if (scanner->last_error_string == NULL) return NULL; return &scanner->rules->rules_table[scanner->last_error_string->rule_idx]; } static int sort_by_cost_desc( const struct YR_RULE_PROFILING_INFO* r1, const struct YR_RULE_PROFILING_INFO* r2) { if (r1->cost < r2->cost) return 1; if (r1->cost > r2->cost) return -1; return 0; } // // yr_scanner_get_profiling_info // // Returns a pointer to an array of YR_RULE_PROFILING_INFO structures with // information about the cost of each rule. The rules are sorted by cost // in descending order and the last item in the array has rule == NULL. // The caller is responsible for freeing the returned array by calling // yr_free. Calling this function only makes sense if YR_PROFILING_ENABLED // is defined, if not, the cost for each rule won't be computed, it will be // set to 0 for all rules. // YR_API YR_RULE_PROFILING_INFO* yr_scanner_get_profiling_info( YR_SCANNER* scanner) { YR_RULE_PROFILING_INFO* profiling_info = yr_malloc( (scanner->rules->num_rules + 1) * sizeof(YR_RULE_PROFILING_INFO)); if (profiling_info == NULL) return NULL; for (uint32_t i = 0; i < scanner->rules->num_rules; i++) { profiling_info[i].rule = &scanner->rules->rules_table[i]; #ifdef YR_PROFILING_ENABLED profiling_info[i].cost = scanner->profiling_info[i].exec_time + (scanner->profiling_info[i].atom_matches * scanner->profiling_info[i].match_time) / YR_MATCH_VERIFICATION_PROFILING_RATE; #else memset(&profiling_info[i], 0, sizeof(YR_RULE_PROFILING_INFO)); #endif } qsort( profiling_info, scanner->rules->num_rules, sizeof(YR_RULE_PROFILING_INFO), (int (*)(const void*, const void*)) sort_by_cost_desc); profiling_info[scanner->rules->num_rules].rule = NULL; profiling_info[scanner->rules->num_rules].cost = 0; return profiling_info; } YR_API void yr_scanner_reset_profiling_info(YR_SCANNER* scanner) { #ifdef YR_PROFILING_ENABLED memset( scanner->profiling_info, 0, scanner->rules->num_rules * sizeof(YR_PROFILING_INFO)); #endif } YR_API int yr_scanner_print_profiling_info(YR_SCANNER* scanner) { printf("\n===== PROFILING INFORMATION =====\n\n"); YR_RULE_PROFILING_INFO* info = yr_scanner_get_profiling_info(scanner); if (info == NULL) return ERROR_INSUFFICIENT_MEMORY; YR_RULE_PROFILING_INFO* rpi = info; while (rpi->rule != NULL) { printf( "%10" PRIu64 " %s:%s: \n", rpi->cost, rpi->rule->ns->name, rpi->rule->identifier); rpi++; } printf("\n=================================\n"); yr_free(info); return ERROR_SUCCESS; } yara-4.5.3/libyara/simple_str.c000066400000000000000000000062161501365277300164450ustar00rootroot00000000000000/* Copyright (c) 2022. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include static bool sstr_vappendf(SIMPLE_STR* ss, const char* fmt, va_list va) { // Create copy because list will get consumed when getting the final length va_list va2; va_copy(va2, va); int size = vsnprintf(NULL, 0, fmt, va2); va_end(va2); if (size < 0) return false; if (ss->cap < ss->len + size + 1) { uint32_t new_size = (ss->len + size) * 2 + 64; char* tmp = yr_realloc(ss->str, new_size); if (!tmp) return false; ss->str = tmp; ss->cap = new_size; } ss->len += vsnprintf(ss->str + ss->len, ss->cap, fmt, va); return true; } SIMPLE_STR* sstr_new(const char* s) { SIMPLE_STR* ss = yr_calloc(1, sizeof(SIMPLE_STR)); if (!ss) return NULL; if (s) { uint32_t slen = strlen(s); ss->str = yr_malloc(slen + 1); if (!ss->str) { yr_free(ss); return NULL; } ss->len = slen; ss->cap = slen; memcpy(ss->str, s, slen + 1); } return ss; } SIMPLE_STR* sstr_newf(const char* fmt, ...) { SIMPLE_STR* ss = sstr_new(NULL); if (!ss) return NULL; va_list va; va_start(va, fmt); bool ret = sstr_vappendf(ss, fmt, va); va_end(va); if (ret) return ss; sstr_free(ss); return NULL; } void sstr_free(SIMPLE_STR* ss) { if (ss) { yr_free(ss->str); yr_free(ss); } } bool sstr_appendf(SIMPLE_STR* ss, const char* fmt, ...) { va_list vlist; va_start(vlist, fmt); bool ret = sstr_vappendf(ss, fmt, vlist); va_end(vlist); return ret; } char* sstr_move(SIMPLE_STR* ss) { char* ret = ss->str; ss->str = NULL; ss->len = 0; ss->cap = 0; return ret; } yara-4.5.3/libyara/sizedstr.c000066400000000000000000000154631501365277300161370ustar00rootroot00000000000000/* Copyright (c) 2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include //////////////////////////////////////////////////////////////////////////////// // ss_compare returns: // 0 if s1 == s2 // -1 if s1 < s2 // 1 if s1 > s2 // int ss_compare(SIZED_STRING* s1, SIZED_STRING* s2) { size_t i = 0; while (s1->length > i && s2->length > i && s1->c_string[i] == s2->c_string[i]) { i++; } if (i == s1->length && i == s2->length) return 0; else if (i == s1->length) return -1; else if (i == s2->length) return 1; else if (s1->c_string[i] < s2->c_string[i]) return -1; else return 1; } //////////////////////////////////////////////////////////////////////////////// // ss_icompare is the case-insensitive version of ss_compare. // int ss_icompare(SIZED_STRING* s1, SIZED_STRING* s2) { size_t i = 0; while (s1->length > i && s2->length > i && yr_lowercase[(uint8_t) s1->c_string[i]] == yr_lowercase[(uint8_t) s2->c_string[i]]) { i++; } if (i == s1->length && i == s2->length) return 0; else if (i == s1->length) return -1; else if (i == s2->length) return 1; else if (s1->c_string[i] < s2->c_string[i]) return -1; else return 1; } //////////////////////////////////////////////////////////////////////////////// // ss_contains returns true if the sized string s1 contains s2. // bool ss_contains(SIZED_STRING* s1, SIZED_STRING* s2) { return memmem(s1->c_string, s1->length, s2->c_string, s2->length) != NULL; } //////////////////////////////////////////////////////////////////////////////// // ss_icontains is the case-insensitive version of ss_contains. // bool ss_icontains(SIZED_STRING* s1, SIZED_STRING* s2) { if (s1->length < s2->length) return false; for (uint32_t i = 0; i < s1->length - s2->length + 1; i++) { uint32_t j = 0; for (j = 0; j < s2->length; j++) if (yr_lowercase[(uint8_t) s1->c_string[i + j]] != yr_lowercase[(uint8_t) s2->c_string[j]]) break; if (j == s2->length) return true; } return false; } //////////////////////////////////////////////////////////////////////////////// // ss_startswith returns true if the sized string s1 starts with s2. // bool ss_startswith(SIZED_STRING* s1, SIZED_STRING* s2) { if (s1->length < s2->length) return false; for (uint32_t i = 0; i < s2->length; i++) { if (s1->c_string[i] != s2->c_string[i]) return false; } return true; } //////////////////////////////////////////////////////////////////////////////// // ss_istartswith is the case-insensitive version of ss_startswith. // bool ss_istartswith(SIZED_STRING* s1, SIZED_STRING* s2) { if (s1->length < s2->length) return false; for (uint32_t i = 0; i < s2->length; i++) { if (yr_lowercase[(uint8_t) s1->c_string[i]] != yr_lowercase[(uint8_t) s2->c_string[i]]) return false; } return true; } //////////////////////////////////////////////////////////////////////////////// // ss_endswith returns true if the sized string s1 ends with s2. // bool ss_endswith(SIZED_STRING* s1, SIZED_STRING* s2) { if (s1->length < s2->length) return false; for (uint32_t i = 0; i < s2->length; i++) { if (s1->c_string[s1->length - s2->length + i] != s2->c_string[i]) return false; } return true; } //////////////////////////////////////////////////////////////////////////////// // ss_iendswith is the case-insensitive version of ss_endswith. // bool ss_iendswith(SIZED_STRING* s1, SIZED_STRING* s2) { if (s1->length < s2->length) return false; for (uint32_t i = 0; i < s2->length; i++) { if (yr_lowercase[(uint8_t) s1->c_string[s1->length - s2->length + i]] != yr_lowercase[(uint8_t) s2->c_string[i]]) return false; } return true; } //////////////////////////////////////////////////////////////////////////////// // ss_dup creates a new copy of a given SIZED_STRING. // SIZED_STRING* ss_dup(SIZED_STRING* s) { SIZED_STRING* result = (SIZED_STRING*) yr_malloc( sizeof(SIZED_STRING) + s->length); if (result == NULL) return NULL; result->length = s->length; result->flags = s->flags; memcpy(result->c_string, s->c_string, s->length + 1); return result; } //////////////////////////////////////////////////////////////////////////////// // ss_new creates a SIZED_STRING from a C string. // SIZED_STRING* ss_new(const char* s) { SIZED_STRING* result; size_t length = strlen(s); result = (SIZED_STRING*) yr_malloc(sizeof(SIZED_STRING) + length); if (result == NULL) return NULL; result->length = (uint32_t) length; result->flags = 0; // Copy the string and the null terminator. strcpy(result->c_string, s); return result; } //////////////////////////////////////////////////////////////////////////////// // Convert a SIZED_STRING to a wide version. It is up to the caller to free // the returned string. // SIZED_STRING* ss_convert_to_wide(SIZED_STRING* s) { SIZED_STRING* wide = (SIZED_STRING*) yr_malloc( sizeof(SIZED_STRING) + s->length * 2); if (wide == NULL) return NULL; for (size_t i = 0; i < s->length; i++) { wide->c_string[i * 2] = s->c_string[i]; wide->c_string[i * 2 + 1] = '\x00'; } wide->length = s->length * 2; wide->flags = s->flags | STRING_FLAGS_WIDE; return wide; } yara-4.5.3/libyara/stack.c000066400000000000000000000075721501365277300153770ustar00rootroot00000000000000/* Copyright (c) 2018. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include //////////////////////////////////////////////////////////////////////////////// // Creates a stack for items of the size specified by item_size. All items // in the stack must have the same size. The stack will have an initial // capacity as specified by initial_capacity and will grow as required when // more objects are pushed. // int yr_stack_create(int initial_capacity, int item_size, YR_STACK** stack) { *stack = (YR_STACK*) yr_malloc(sizeof(YR_STACK)); if (*stack == NULL) return ERROR_INSUFFICIENT_MEMORY; (*stack)->items = yr_malloc(initial_capacity * item_size); if ((*stack)->items == NULL) { yr_free(*stack); *stack = NULL; return ERROR_INSUFFICIENT_MEMORY; } (*stack)->capacity = initial_capacity; (*stack)->item_size = item_size; (*stack)->top = 0; return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Destroys a stack and deallocates all its resources. // void yr_stack_destroy(YR_STACK* stack) { yr_free(stack->items); yr_free(stack); } //////////////////////////////////////////////////////////////////////////////// // Pushes an item into the stack. If the stack has reached its capacity the // function tries to double the capacity. This operation can fail with // ERROR_INSUFFICIENT_MEMORY. // int yr_stack_push(YR_STACK* stack, void* item) { if (stack->top == stack->capacity) { void* items = yr_realloc( stack->items, 2 * stack->capacity * stack->item_size); if (items == NULL) return ERROR_INSUFFICIENT_MEMORY; stack->items = items; stack->capacity *= 2; } memcpy( (uint8_t*) stack->items + stack->top * stack->item_size, item, stack->item_size); stack->top++; return ERROR_SUCCESS; } //////////////////////////////////////////////////////////////////////////////// // Pops an item from the stack. The caller must pass pointer to a buffer // where the function will copy the item. The buffer must have enough space // to hold the item. Returns 1 if an item could be poped and 0 if the stack // was already empty. // int yr_stack_pop(YR_STACK* stack, void* item) { if (stack->top == 0) // Return 0 if stack is empty. return 0; stack->top--; memcpy( item, (uint8_t*) stack->items + stack->top * stack->item_size, stack->item_size); return 1; } yara-4.5.3/libyara/stino.settings000066400000000000000000000001031501365277300170230ustar00rootroot00000000000000{ "baudrate": 4, "line_ending": 1, "serial_port": 1 }yara-4.5.3/libyara/stopwatch.c000066400000000000000000000102051501365277300162710ustar00rootroot00000000000000/* Copyright (c) 2017. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #if defined(_WIN32) void yr_stopwatch_start(YR_STOPWATCH* sw) { QueryPerformanceFrequency(&sw->frequency); QueryPerformanceCounter(&sw->start); } uint64_t yr_stopwatch_elapsed_ns(YR_STOPWATCH* sw) { LARGE_INTEGER li; QueryPerformanceCounter(&li); return (li.QuadPart - sw->start.QuadPart) * 1000000000ULL / sw->frequency.QuadPart; } #elif defined(__APPLE__) && defined(__MACH__) void yr_stopwatch_start(YR_STOPWATCH* sw) { mach_timebase_info(&sw->timebase); sw->start = mach_absolute_time(); } uint64_t yr_stopwatch_elapsed_ns(YR_STOPWATCH* sw) { uint64_t now = mach_absolute_time(); return ((now - sw->start) * sw->timebase.numer) / sw->timebase.denom; } #elif defined(HAVE_CLOCK_GETTIME) #define timespecsub(tsp, usp, vsp) \ do \ { \ (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ if ((vsp)->tv_nsec < 0) \ { \ (vsp)->tv_sec--; \ (vsp)->tv_nsec += 1000000000L; \ } \ } while (0) void yr_stopwatch_start(YR_STOPWATCH* stopwatch) { clock_gettime(CLOCK_MONOTONIC, &stopwatch->ts_start); } uint64_t yr_stopwatch_elapsed_ns(YR_STOPWATCH* stopwatch) { struct timespec ts_stop; struct timespec ts_elapsed; clock_gettime(CLOCK_MONOTONIC, &ts_stop); timespecsub(&ts_stop, &stopwatch->ts_start, &ts_elapsed); return ts_elapsed.tv_sec * 1000000000ULL + ts_elapsed.tv_nsec; } #else #include #define timevalsub(tvp, uvp, vvp) \ do \ { \ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ if ((vvp)->tv_usec < 0) \ { \ (vvp)->tv_sec--; \ (vvp)->tv_usec += 1000000L; \ } \ } while (0) void yr_stopwatch_start(YR_STOPWATCH* stopwatch) { gettimeofday(&stopwatch->tv_start, NULL); } uint64_t yr_stopwatch_elapsed_ns(YR_STOPWATCH* stopwatch) { struct timeval tv_stop; struct timeval tv_elapsed; gettimeofday(&tv_stop, NULL); timevalsub(&tv_stop, &stopwatch->tv_start, &tv_elapsed); return tv_elapsed.tv_sec * 1000000000ULL + tv_elapsed.tv_usec * 1000ULL; } #endif yara-4.5.3/libyara/stream.c000066400000000000000000000036261501365277300155610ustar00rootroot00000000000000/* Copyright (c) 2015. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include size_t yr_stream_read(void* ptr, size_t size, size_t count, YR_STREAM* stream) { if (stream->read == NULL) return 0; return stream->read(ptr, size, count, stream->user_data); } size_t yr_stream_write( const void* ptr, size_t size, size_t count, YR_STREAM* stream) { if (stream->write == NULL) return 0; return stream->write(ptr, size, count, stream->user_data); } yara-4.5.3/libyara/strutils.c000066400000000000000000000140531501365277300161530ustar00rootroot00000000000000/* Copyright (c) 2007-2014. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include uint64_t xtoi(const char* hexstr) { size_t i; size_t l = strlen(hexstr); uint64_t r = 0; for (i = 0; i < l; i++) { switch (hexstr[i]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': r |= ((uint64_t) (hexstr[i] - '0')) << ((l - i - 1) * 4); break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': r |= ((uint64_t) (hexstr[i] - 'a' + 10)) << ((l - i - 1) * 4); break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': r |= ((uint64_t) (hexstr[i] - 'A' + 10)) << ((l - i - 1) * 4); break; default: i = l; // force loop exit } } return r; } /* strlcpy and strlcat are defined in FreeBSD and OpenBSD, the following implementations were taken from OpenBSD. */ #if !HAVE_STRLCPY && !defined(strlcpy) size_t strlcpy(char* dst, const char* src, size_t size) { register char* d = dst; register const char* s = src; register size_t n = size; // Copy as many bytes as will fit if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } // Not enough room in dst, add NUL and traverse rest of src if (n == 0) { if (size != 0) *d = '\0'; // NULL-terminate dst while (*s++) ; } return (s - src - 1); // count does not include NULL } #endif #if !HAVE_STRLCAT && !defined(strlcat) size_t strlcat(char* dst, const char* src, size_t size) { register char* d = dst; register const char* s = src; register size_t n = size; size_t dlen; // Find the end of dst and adjust bytes left but don't go past end while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = size - dlen; if (n == 0) return (dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return (dlen + (s - src)); // count does not include NULL } #endif int strnlen_w(const char* w_str) { int len = 0; while (w_str[0] || w_str[1]) { w_str += 2; len += 1; } return len; } int strcmp_w(const char* w_str, const char* str) { while (*str != 0 && w_str[0] == *str && w_str[1] == 0) { w_str += 2; str += 1; } // Higher-order byte of wide char non-zero? -> w_str is larger than str if (w_str[1] != 0) return 1; return w_str[0] - *str; } size_t strlcpy_w(char* dst, const char* w_src, size_t n) { register char* d = dst; register const char* s = w_src; while (n > 1 && *s != 0) { *d = *s; d += 1; n -= 1; s += 2; } while (*s) s += 2; *d = '\0'; return (s - w_src) / 2; } #if !HAVE_MEMMEM && !defined(memmem) void* memmem( const void* haystack, size_t haystack_size, const void* needle, size_t needle_size) { char* sp = (char*) haystack; char* pp = (char*) needle; char* eos; if (haystack == NULL || haystack_size == 0 || needle == NULL || needle_size == 0) return NULL; eos = sp + haystack_size - needle_size; while (sp <= eos) { if (*sp == *pp && memcmp(sp, pp, needle_size) == 0) return sp; sp++; } return NULL; } #endif /////////////////////////////////////////////////////////////////////////////// // This our own implementation of isalnum(). The library version is locale // dependent in some platforms and can consider non-ASCII characters to be // alphanumeric. // int yr_isalnum(const uint8_t* s) { return (*s >= 0x30 && *s <= 0x39) || (*s >= 0x41 && *s <= 0x5a) || (*s >= 0x61 && *s <= 0x7a); } ////////////////////////////////////////////////////////////////////////// // This our own implementation of vasprintf(), as it is not available on // some platforms. It is based on the implementation of vsnprintf but it // allocates memory using yr_malloc, and therefore the caller must free // the memory using yr_free. // void yr_vasprintf(char** strp, const char* fmt, va_list ap) { va_list ap_copy; va_copy(ap_copy, ap); *strp = NULL; int len = vsnprintf(NULL, 0, fmt, ap_copy); va_end(ap_copy); if (len < 0) return; *strp = (char*) yr_malloc(len + 1); if (*strp == NULL) return; vsnprintf(*strp, len + 1, fmt, ap); } ////////////////////////////////////////////////////////////////////////// // This our own implementation of asprintf(), see yr_vasprintf() for details. // void yr_asprintf(char** strp, const char* fmt, ...) { va_list ap; va_start(ap, fmt); yr_vasprintf(strp, fmt, ap); va_end(ap); } yara-4.5.3/libyara/threading.c000066400000000000000000000103261501365277300162260ustar00rootroot00000000000000/* Copyright (c) 2016. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #if defined(_WIN32) || defined(__CYGWIN__) YR_THREAD_ID yr_current_thread_id(void) { return GetCurrentThreadId(); } int yr_mutex_create(YR_MUTEX* mutex) { *mutex = CreateMutex(NULL, FALSE, NULL); if (*mutex == NULL) return ERROR_INTERNAL_FATAL_ERROR; return ERROR_SUCCESS; } int yr_mutex_destroy(YR_MUTEX* mutex) { if (CloseHandle(*mutex) == FALSE) return ERROR_INTERNAL_FATAL_ERROR; return ERROR_SUCCESS; } int yr_mutex_lock(YR_MUTEX* mutex) { if (WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED) return ERROR_INTERNAL_FATAL_ERROR; return ERROR_SUCCESS; } int yr_mutex_unlock(YR_MUTEX* mutex) { if (ReleaseMutex(*mutex) == FALSE) return ERROR_INTERNAL_FATAL_ERROR; return ERROR_SUCCESS; } int yr_thread_storage_create(YR_THREAD_STORAGE_KEY* storage) { *storage = TlsAlloc(); if (*storage == TLS_OUT_OF_INDEXES) return ERROR_INTERNAL_FATAL_ERROR; return ERROR_SUCCESS; } int yr_thread_storage_destroy(YR_THREAD_STORAGE_KEY* storage) { if (TlsFree(*storage) == FALSE) return ERROR_INTERNAL_FATAL_ERROR; return ERROR_SUCCESS; } int yr_thread_storage_set_value(YR_THREAD_STORAGE_KEY* storage, void* value) { if (TlsSetValue(*storage, value) == FALSE) return ERROR_INTERNAL_FATAL_ERROR; return ERROR_SUCCESS; } void* yr_thread_storage_get_value(YR_THREAD_STORAGE_KEY* storage) { return TlsGetValue(*storage); } #else // POSIX implementation YR_THREAD_ID yr_current_thread_id(void) { return pthread_self(); } int yr_mutex_create(YR_MUTEX* mutex) { if (pthread_mutex_init(mutex, NULL) != 0) return ERROR_INTERNAL_FATAL_ERROR; return ERROR_SUCCESS; } int yr_mutex_destroy(YR_MUTEX* mutex) { if (pthread_mutex_destroy(mutex) != 0) return ERROR_INTERNAL_FATAL_ERROR; return ERROR_SUCCESS; } int yr_mutex_lock(YR_MUTEX* mutex) { if (pthread_mutex_lock(mutex) != 0) return ERROR_INTERNAL_FATAL_ERROR; return ERROR_SUCCESS; } int yr_mutex_unlock(YR_MUTEX* mutex) { if (pthread_mutex_unlock(mutex) != 0) return ERROR_INTERNAL_FATAL_ERROR; return ERROR_SUCCESS; } int yr_thread_storage_create(YR_THREAD_STORAGE_KEY* storage) { if (pthread_key_create(storage, NULL) != 0) return ERROR_INTERNAL_FATAL_ERROR; return ERROR_SUCCESS; } int yr_thread_storage_destroy(YR_THREAD_STORAGE_KEY* storage) { if (pthread_key_delete(*storage) != 0) return ERROR_INTERNAL_FATAL_ERROR; return ERROR_SUCCESS; } int yr_thread_storage_set_value(YR_THREAD_STORAGE_KEY* storage, void* value) { if (pthread_setspecific(*storage, value) != 0) return ERROR_INTERNAL_FATAL_ERROR; return ERROR_SUCCESS; } void* yr_thread_storage_get_value(YR_THREAD_STORAGE_KEY* storage) { return pthread_getspecific(*storage); } #endif yara-4.5.3/libyara/tlshc/000077500000000000000000000000001501365277300152305ustar00rootroot00000000000000yara-4.5.3/libyara/tlshc/tlsh.c000066400000000000000000000022711501365277300163500ustar00rootroot00000000000000#include #include #include "tlsh_impl.h" Tlsh* tlsh_new() { Tlsh* tlsh = malloc(sizeof(Tlsh)); if (!tlsh) return NULL; tlsh->impl = tlsh_impl_new(); if (!tlsh->impl) { free(tlsh); return NULL; } return tlsh; } void tlsh_free(Tlsh* tlsh) { if (tlsh) { tlsh_impl_free(tlsh->impl); free(tlsh); } } int tlsh_update(Tlsh* tlsh, const unsigned char* data, unsigned int len) { int tlsh_option = 0; if (tlsh->impl) { int res = tlsh_impl_update(tlsh->impl, data, len, tlsh_option); if (res) { return 1; } } return 0; } void tlsh_reset(Tlsh* tlsh) { if (tlsh->impl) tlsh_impl_reset(tlsh->impl); } int tlsh_final( Tlsh* tlsh, const unsigned char* data, unsigned int len, int tlsh_option) { if (tlsh->impl) { if ((data != NULL) && (len > 0)) { int res = tlsh_impl_update(tlsh->impl, data, len, tlsh_option); if (res) { return 1; } } tlsh_impl_final(tlsh->impl, tlsh_option); } return 0; } const char* tlsh_get_hash(Tlsh* tlsh, bool showvers) { if (tlsh->impl) return tlsh_impl_hash(tlsh->impl, showvers); else return ""; }yara-4.5.3/libyara/tlshc/tlsh_impl.c000066400000000000000000000760671501365277300174070ustar00rootroot00000000000000#include "tlsh_impl.h" #include #include "tlsh_util.h" #include #include #include #define RANGE_LVALUE 256 #define RANGE_QRATIO 16 static void find_quartile( unsigned int *q1, unsigned int *q2, unsigned int *q3, const unsigned int *a_bucket); static unsigned int partition( unsigned int *buf, unsigned int left, unsigned int right); static void tlsh_impl_fast_update5( TlshImpl *impl, const unsigned char *data, unsigned int len, int tlsh_option); // Pearson's sample random table #if defined BUCKETS_48 static unsigned char v_table48[256] = { 1, 39, 1, 12, 32, 34, 6, 22, 25, 1, 6, 36, 48, 38, 44, 19, 14, 5, 21, 37, 17, 37, 26, 32, 16, 47, 24, 34, 44, 46, 38, 8, 14, 33, 8, 7, 45, 48, 48, 2, 29, 5, 33, 18, 45, 0, 31, 30, 25, 11, 46, 22, 38, 45, 48, 34, 24, 48, 20, 22, 48, 35, 5, 43, 1, 42, 9, 22, 12, 48, 34, 31, 16, 5, 31, 7, 15, 14, 39, 48, 30, 25, 19, 10, 18, 10, 10, 3, 48, 27, 17, 43, 38, 35, 0, 48, 36, 8, 4, 27, 32, 37, 14, 4, 34, 30, 43, 13, 9, 48, 24, 27, 23, 20, 31, 30, 35, 40, 9, 3, 26, 11, 44, 32, 40, 18, 4, 10, 42, 30, 0, 39, 12, 35, 13, 26, 47, 26, 48, 46, 33, 18, 15, 8, 26, 7, 19, 23, 48, 14, 3, 6, 7, 11, 7, 28, 42, 5, 23, 35, 29, 29, 15, 46, 31, 47, 41, 16, 9, 41, 33, 32, 25, 16, 37, 27, 22, 25, 2, 13, 46, 20, 9, 1, 38, 36, 15, 20, 10, 23, 21, 37, 27, 44, 19, 28, 24, 48, 42, 4, 29, 12, 21, 48, 19, 13, 39, 11, 41, 40, 42, 3, 6, 0, 11, 33, 20, 47, 2, 12, 21, 36, 21, 28, 44, 36, 18, 28, 41, 6, 15, 8, 41, 40, 17, 4, 39, 47, 2, 24, 3, 17, 28, 0, 48, 29, 45, 45, 2, 43, 16, 43, 23, 13, 40, 17, }; #else static unsigned char v_table[256] = { 1, 87, 49, 12, 176, 178, 102, 166, 121, 193, 6, 84, 249, 230, 44, 163, 14, 197, 213, 181, 161, 85, 218, 80, 64, 239, 24, 226, 236, 142, 38, 200, 110, 177, 104, 103, 141, 253, 255, 50, 77, 101, 81, 18, 45, 96, 31, 222, 25, 107, 190, 70, 86, 237, 240, 34, 72, 242, 20, 214, 244, 227, 149, 235, 97, 234, 57, 22, 60, 250, 82, 175, 208, 5, 127, 199, 111, 62, 135, 248, 174, 169, 211, 58, 66, 154, 106, 195, 245, 171, 17, 187, 182, 179, 0, 243, 132, 56, 148, 75, 128, 133, 158, 100, 130, 126, 91, 13, 153, 246, 216, 219, 119, 68, 223, 78, 83, 88, 201, 99, 122, 11, 92, 32, 136, 114, 52, 10, 138, 30, 48, 183, 156, 35, 61, 26, 143, 74, 251, 94, 129, 162, 63, 152, 170, 7, 115, 167, 241, 206, 3, 150, 55, 59, 151, 220, 90, 53, 23, 131, 125, 173, 15, 238, 79, 95, 89, 16, 105, 137, 225, 224, 217, 160, 37, 123, 118, 73, 2, 157, 46, 116, 9, 145, 134, 228, 207, 212, 202, 215, 69, 229, 27, 188, 67, 124, 168, 252, 42, 4, 29, 108, 21, 247, 19, 205, 39, 203, 233, 40, 186, 147, 198, 192, 155, 33, 164, 191, 98, 204, 165, 180, 117, 76, 140, 36, 210, 172, 41, 54, 159, 8, 185, 232, 113, 196, 231, 47, 146, 120, 51, 65, 28, 144, 254, 221, 93, 189, 194, 139, 112, 43, 71, 109, 184, 209}; #endif // Pearson's algorithm static unsigned char b_mapping( unsigned char salt, unsigned char i, unsigned char j, unsigned char k) { unsigned char h = 0; h = v_table[h ^ salt]; h = v_table[h ^ i]; h = v_table[h ^ j]; h = v_table[h ^ k]; return h; } #if defined BUCKETS_48 #define fast_b_mapping(ms, i, j, k) \ (v_table48[v_table[v_table[ms ^ i] ^ j] ^ k]) #else #define fast_b_mapping(ms, i, j, k) (v_table[v_table[v_table[ms ^ i] ^ j] ^ k]) #endif //////////////////////////////////////////////////////////////////////////////////////////// #if SLIDING_WND_SIZE == 5 #define SLIDING_WND_SIZE_M1 4 #elif SLIDING_WND_SIZE == 4 #define SLIDING_WND_SIZE_M1 3 #elif SLIDING_WND_SIZE == 6 #define SLIDING_WND_SIZE_M1 5 #elif SLIDING_WND_SIZE == 7 #define SLIDING_WND_SIZE_M1 6 #elif SLIDING_WND_SIZE == 8 #define SLIDING_WND_SIZE_M1 7 #endif #define RNG_SIZE SLIDING_WND_SIZE #define RNG_IDX(i) ((i + RNG_SIZE) % RNG_SIZE) TlshImpl *tlsh_impl_new() { TlshImpl *impl = calloc(1, sizeof(TlshImpl)); if (!impl) return NULL; return impl; } void tlsh_impl_free(TlshImpl *impl) { if (impl) { free(impl->a_bucket); free(impl->lsh_code); free(impl); } } void tlsh_impl_reset(TlshImpl *impl) { free(impl->a_bucket); impl->a_bucket = NULL; memset(impl->slide_window, 0, sizeof impl->slide_window); free(impl->lsh_code); impl->lsh_code = NULL; memset(&impl->lsh_bin, 0, sizeof impl->lsh_bin); impl->data_len = 0; impl->lsh_code_valid = false; } int tlsh_impl_update( TlshImpl *impl, const unsigned char *data, unsigned int len, int tlsh_option) { if (impl->lsh_code_valid) { fprintf(stderr, "call to update() on a tlsh that is already valid\n"); return 1; } unsigned int fed_len = impl->data_len; if (impl->a_bucket == NULL) { impl->a_bucket = malloc( BUCKETS * sizeof(unsigned int)); // TODO error handling if (!impl->a_bucket) { return 1; } memset(impl->a_bucket, 0, sizeof(int) * BUCKETS); } #if SLIDING_WND_SIZE == 5 if (TLSH_CHECKSUM_LEN == 1) { tlsh_impl_fast_update5(impl, data, len, tlsh_option); #ifndef CHECKSUM_0B if ((tlsh_option & TLSH_OPTION_THREADED) || (tlsh_option & TLSH_OPTION_PRIVATE)) { impl->lsh_bin.checksum[0] = 0; } #endif return 0; } #endif int j = (int) (impl->data_len % RNG_SIZE); for (unsigned int i = 0; i < len; i++, fed_len++, j = RNG_IDX(j + 1)) { impl->slide_window[j] = data[i]; if (fed_len >= SLIDING_WND_SIZE_M1) { // only calculate when input >= 5 bytes int j_1 = RNG_IDX(j - 1); int j_2 = RNG_IDX(j - 2); int j_3 = RNG_IDX(j - 3); #if SLIDING_WND_SIZE >= 5 int j_4 = RNG_IDX(j - 4); #endif #if SLIDING_WND_SIZE >= 6 int j_5 = RNG_IDX(j - 5); #endif #if SLIDING_WND_SIZE >= 7 int j_6 = RNG_IDX(j - 6); #endif #if SLIDING_WND_SIZE >= 8 int j_7 = RNG_IDX(j - 7); #endif #ifndef CHECKSUM_0B for (int k = 0; k < TLSH_CHECKSUM_LEN; k++) { if (k == 0) { // b_mapping(0, ... ) impl->lsh_bin.checksum[k] = fast_b_mapping( 1, impl->slide_window[j], impl->slide_window[j_1], impl->lsh_bin.checksum[k]); } else { // use calculated 1 byte checksums to expand the total checksum to 3 // bytes impl->lsh_bin.checksum[k] = b_mapping( impl->lsh_bin.checksum[k - 1], impl->slide_window[j], impl->slide_window[j_1], impl->lsh_bin.checksum[k]); } } #endif unsigned char r; // b_mapping(2, ... ) r = fast_b_mapping( 49, impl->slide_window[j], impl->slide_window[j_1], impl->slide_window[j_2]); impl->a_bucket[r]++; // b_mapping(3, ... ) r = fast_b_mapping( 12, impl->slide_window[j], impl->slide_window[j_1], impl->slide_window[j_3]); impl->a_bucket[r]++; // b_mapping(5, ... ) r = fast_b_mapping( 178, impl->slide_window[j], impl->slide_window[j_2], impl->slide_window[j_3]); impl->a_bucket[r]++; #if SLIDING_WND_SIZE >= 5 // b_mapping(7, ... ) r = fast_b_mapping( 166, impl->slide_window[j], impl->slide_window[j_2], impl->slide_window[j_4]); impl->a_bucket[r]++; // b_mapping(11, ... ) r = fast_b_mapping( 84, impl->slide_window[j], impl->slide_window[j_1], impl->slide_window[j_4]); impl->a_bucket[r]++; // b_mapping(13, ... ) r = fast_b_mapping( 230, impl->slide_window[j], impl->slide_window[j_3], impl->slide_window[j_4]); impl->a_bucket[r]++; #endif #if SLIDING_WND_SIZE >= 6 // b_mapping(17, ... ) r = fast_b_mapping( 197, this->slide_window[j], this->slide_window[j_1], this->slide_window[j_5]); this->a_bucket[r]++; // b_mapping(19, ... ) r = fast_b_mapping( 181, this->slide_window[j], this->slide_window[j_2], this->slide_window[j_5]); this->a_bucket[r]++; // b_mapping(23, ... ) r = fast_b_mapping( 80, this->slide_window[j], this->slide_window[j_3], this->slide_window[j_5]); this->a_bucket[r]++; // b_mapping(29, ... ) r = fast_b_mapping( 142, this->slide_window[j], this->slide_window[j_4], this->slide_window[j_5]); this->a_bucket[r]++; #endif #if SLIDING_WND_SIZE >= 7 // b_mapping(31, ... ) r = fast_b_mapping( 200, this->slide_window[j], this->slide_window[j_1], this->slide_window[j_6]); this->a_bucket[r]++; // b_mapping(37, ... ) r = fast_b_mapping( 253, this->slide_window[j], this->slide_window[j_2], this->slide_window[j_6]); this->a_bucket[r]++; // b_mapping(41, ... ) r = fast_b_mapping( 101, this->slide_window[j], this->slide_window[j_3], this->slide_window[j_6]); this->a_bucket[r]++; // b_mapping(43, ... ) r = fast_b_mapping( 18, this->slide_window[j], this->slide_window[j_4], this->slide_window[j_6]); this->a_bucket[r]++; // b_mapping(47, ... ) r = fast_b_mapping( 222, this->slide_window[j], this->slide_window[j_5], this->slide_window[j_6]); this->a_bucket[r]++; #endif #if SLIDING_WND_SIZE >= 8 // b_mapping(53, ... ) r = fast_b_mapping( 237, this->slide_window[j], this->slide_window[j_1], this->slide_window[j_7]); this->a_bucket[r]++; // b_mapping(59, ... ) r = fast_b_mapping( 214, this->slide_window[j], this->slide_window[j_2], this->slide_window[j_7]); this->a_bucket[r]++; // b_mapping(61, ... ) r = fast_b_mapping( 227, this->slide_window[j], this->slide_window[j_3], this->slide_window[j_7]); this->a_bucket[r]++; // b_mapping(67, ... ) r = fast_b_mapping( 22, this->slide_window[j], this->slide_window[j_4], this->slide_window[j_7]); this->a_bucket[r]++; // b_mapping(71, ... ) r = fast_b_mapping( 175, this->slide_window[j], this->slide_window[j_5], this->slide_window[j_7]); this->a_bucket[r]++; // b_mapping(73, ... ) r = fast_b_mapping( 5, this->slide_window[j], this->slide_window[j_6], this->slide_window[j_7]); this->a_bucket[r]++; #endif } } impl->data_len += len; #ifndef CHECKSUM_0B if ((tlsh_option & TLSH_OPTION_THREADED) || (tlsh_option & TLSH_OPTION_PRIVATE)) { for (int k = 0; k < TLSH_CHECKSUM_LEN; k++) { impl->lsh_bin.checksum[k] = 0; } } #endif return 0; } ///////////////////////////////////////////////////////////////////////////// // update for the case when SLIDING_WND_SIZE==5 // have different optimized functions for // default TLSH // threaded TLSH // private TLSH ///////////////////////////////////////////////////////////////////////////// static void raw_fast_update5( // inputs const unsigned char *data, unsigned int len, unsigned int fed_len, // outputs unsigned int *a_bucket, unsigned char *ret_checksum, unsigned char *slide_window); static void raw_fast_update5_private( // inputs const unsigned char *data, unsigned int len, unsigned int fed_len, // outputs unsigned int *a_bucket, unsigned char *slide_window); static void tlsh_impl_fast_update5( TlshImpl *impl, const unsigned char *data, unsigned int len, int tlsh_option) { if (tlsh_option & TLSH_OPTION_PRIVATE) { raw_fast_update5_private( data, len, impl->data_len, impl->a_bucket, impl->slide_window); impl->data_len += len; impl->lsh_bin.checksum[0] = 0; } else { raw_fast_update5( data, len, impl->data_len, impl->a_bucket, &(impl->lsh_bin.checksum[0]), impl->slide_window); impl->data_len += len; } } static void raw_fast_update5( // inputs const unsigned char *data, unsigned int len, unsigned int fed_len, // outputs unsigned int *a_bucket, unsigned char *ret_checksum, unsigned char *slide_window) { int j = (int) (fed_len % RNG_SIZE); unsigned char checksum = *ret_checksum; unsigned int start_i = 0; if (fed_len < SLIDING_WND_SIZE_M1) { int extra = SLIDING_WND_SIZE_M1 - fed_len; start_i = extra; j = (j + extra) % RNG_SIZE; } for (unsigned int i = start_i; i < len;) { // only calculate when input >= 5 bytes if ((i >= 4) && (i + 5 < len)) { unsigned char a0 = data[i - 4]; unsigned char a1 = data[i - 3]; unsigned char a2 = data[i - 2]; unsigned char a3 = data[i - 1]; unsigned char a4 = data[i]; unsigned char a5 = data[i + 1]; unsigned char a6 = data[i + 2]; unsigned char a7 = data[i + 3]; unsigned char a8 = data[i + 4]; checksum = fast_b_mapping(1, a4, a3, checksum); a_bucket[fast_b_mapping(49, a4, a3, a2)]++; a_bucket[fast_b_mapping(12, a4, a3, a1)]++; a_bucket[fast_b_mapping(178, a4, a2, a1)]++; a_bucket[fast_b_mapping(166, a4, a2, a0)]++; a_bucket[fast_b_mapping(84, a4, a3, a0)]++; a_bucket[fast_b_mapping(230, a4, a1, a0)]++; checksum = fast_b_mapping(1, a5, a4, checksum); a_bucket[fast_b_mapping(49, a5, a4, a3)]++; a_bucket[fast_b_mapping(12, a5, a4, a2)]++; a_bucket[fast_b_mapping(178, a5, a3, a2)]++; a_bucket[fast_b_mapping(166, a5, a3, a1)]++; a_bucket[fast_b_mapping(84, a5, a4, a1)]++; a_bucket[fast_b_mapping(230, a5, a2, a1)]++; checksum = fast_b_mapping(1, a6, a5, checksum); a_bucket[fast_b_mapping(49, a6, a5, a4)]++; a_bucket[fast_b_mapping(12, a6, a5, a3)]++; a_bucket[fast_b_mapping(178, a6, a4, a3)]++; a_bucket[fast_b_mapping(166, a6, a4, a2)]++; a_bucket[fast_b_mapping(84, a6, a5, a2)]++; a_bucket[fast_b_mapping(230, a6, a3, a2)]++; checksum = fast_b_mapping(1, a7, a6, checksum); a_bucket[fast_b_mapping(49, a7, a6, a5)]++; a_bucket[fast_b_mapping(12, a7, a6, a4)]++; a_bucket[fast_b_mapping(178, a7, a5, a4)]++; a_bucket[fast_b_mapping(166, a7, a5, a3)]++; a_bucket[fast_b_mapping(84, a7, a6, a3)]++; a_bucket[fast_b_mapping(230, a7, a4, a3)]++; checksum = fast_b_mapping(1, a8, a7, checksum); a_bucket[fast_b_mapping(49, a8, a7, a6)]++; a_bucket[fast_b_mapping(12, a8, a7, a5)]++; a_bucket[fast_b_mapping(178, a8, a6, a5)]++; a_bucket[fast_b_mapping(166, a8, a6, a4)]++; a_bucket[fast_b_mapping(84, a8, a7, a4)]++; a_bucket[fast_b_mapping(230, a8, a5, a4)]++; i = i + 5; j = RNG_IDX(j + 5); } else { slide_window[j] = data[i]; int j_1 = RNG_IDX(j - 1); if (i >= 1) { slide_window[j_1] = data[i - 1]; } int j_2 = RNG_IDX(j - 2); if (i >= 2) { slide_window[j_2] = data[i - 2]; } int j_3 = RNG_IDX(j - 3); if (i >= 3) { slide_window[j_3] = data[i - 3]; } int j_4 = RNG_IDX(j - 4); if (i >= 4) { slide_window[j_4] = data[i - 4]; } checksum = fast_b_mapping( 1, slide_window[j], slide_window[j_1], checksum); a_bucket[fast_b_mapping( 49, slide_window[j], slide_window[j_1], slide_window[j_2])]++; a_bucket[fast_b_mapping( 12, slide_window[j], slide_window[j_1], slide_window[j_3])]++; a_bucket[fast_b_mapping( 178, slide_window[j], slide_window[j_2], slide_window[j_3])]++; a_bucket[fast_b_mapping( 166, slide_window[j], slide_window[j_2], slide_window[j_4])]++; a_bucket[fast_b_mapping( 84, slide_window[j], slide_window[j_1], slide_window[j_4])]++; a_bucket[fast_b_mapping( 230, slide_window[j], slide_window[j_3], slide_window[j_4])]++; i++; j = RNG_IDX(j + 1); } } *ret_checksum = checksum; } static void raw_fast_update5_private( // inputs const unsigned char *data, unsigned int len, unsigned int fed_len, // outputs unsigned int *a_bucket, unsigned char *slide_window) { int j = (int) (fed_len % RNG_SIZE); unsigned int start_i = 0; if (fed_len < SLIDING_WND_SIZE_M1) { int extra = SLIDING_WND_SIZE_M1 - fed_len; start_i = extra; j = (j + extra) % RNG_SIZE; } for (unsigned int i = start_i; i < len;) { // only calculate when input >= 5 bytes if ((i >= 4) && (i + 5 < len)) { unsigned char a0 = data[i - 4]; unsigned char a1 = data[i - 3]; unsigned char a2 = data[i - 2]; unsigned char a3 = data[i - 1]; unsigned char a4 = data[i]; unsigned char a5 = data[i + 1]; unsigned char a6 = data[i + 2]; unsigned char a7 = data[i + 3]; unsigned char a8 = data[i + 4]; a_bucket[fast_b_mapping(49, a4, a3, a2)]++; a_bucket[fast_b_mapping(12, a4, a3, a1)]++; a_bucket[fast_b_mapping(178, a4, a2, a1)]++; a_bucket[fast_b_mapping(166, a4, a2, a0)]++; a_bucket[fast_b_mapping(84, a4, a3, a0)]++; a_bucket[fast_b_mapping(230, a4, a1, a0)]++; a_bucket[fast_b_mapping(49, a5, a4, a3)]++; a_bucket[fast_b_mapping(12, a5, a4, a2)]++; a_bucket[fast_b_mapping(178, a5, a3, a2)]++; a_bucket[fast_b_mapping(166, a5, a3, a1)]++; a_bucket[fast_b_mapping(84, a5, a4, a1)]++; a_bucket[fast_b_mapping(230, a5, a2, a1)]++; a_bucket[fast_b_mapping(49, a6, a5, a4)]++; a_bucket[fast_b_mapping(12, a6, a5, a3)]++; a_bucket[fast_b_mapping(178, a6, a4, a3)]++; a_bucket[fast_b_mapping(166, a6, a4, a2)]++; a_bucket[fast_b_mapping(84, a6, a5, a2)]++; a_bucket[fast_b_mapping(230, a6, a3, a2)]++; a_bucket[fast_b_mapping(49, a7, a6, a5)]++; a_bucket[fast_b_mapping(12, a7, a6, a4)]++; a_bucket[fast_b_mapping(178, a7, a5, a4)]++; a_bucket[fast_b_mapping(166, a7, a5, a3)]++; a_bucket[fast_b_mapping(84, a7, a6, a3)]++; a_bucket[fast_b_mapping(230, a7, a4, a3)]++; a_bucket[fast_b_mapping(49, a8, a7, a6)]++; a_bucket[fast_b_mapping(12, a8, a7, a5)]++; a_bucket[fast_b_mapping(178, a8, a6, a5)]++; a_bucket[fast_b_mapping(166, a8, a6, a4)]++; a_bucket[fast_b_mapping(84, a8, a7, a4)]++; a_bucket[fast_b_mapping(230, a8, a5, a4)]++; i = i + 5; j = RNG_IDX(j + 5); } else { slide_window[j] = data[i]; int j_1 = RNG_IDX(j - 1); if (i >= 1) { slide_window[j_1] = data[i - 1]; } int j_2 = RNG_IDX(j - 2); if (i >= 2) { slide_window[j_2] = data[i - 2]; } int j_3 = RNG_IDX(j - 3); if (i >= 3) { slide_window[j_3] = data[i - 3]; } int j_4 = RNG_IDX(j - 4); if (i >= 4) { slide_window[j_4] = data[i - 4]; } a_bucket[fast_b_mapping( 49, slide_window[j], slide_window[j_1], slide_window[j_2])]++; a_bucket[fast_b_mapping( 12, slide_window[j], slide_window[j_1], slide_window[j_3])]++; a_bucket[fast_b_mapping( 178, slide_window[j], slide_window[j_2], slide_window[j_3])]++; a_bucket[fast_b_mapping( 166, slide_window[j], slide_window[j_2], slide_window[j_4])]++; a_bucket[fast_b_mapping( 84, slide_window[j], slide_window[j_1], slide_window[j_4])]++; a_bucket[fast_b_mapping( 230, slide_window[j], slide_window[j_3], slide_window[j_4])]++; i++; j = RNG_IDX(j + 1); } } } ///////////////////////////////////////////////////////////////////////////// // fc_cons_option - a bitfield // 0 default // 1 force (now the default) // 2 conservative // 4 do not delete a_bucket ///////////////////////////////////////////////////////////////////////////// /* to signal the class there is no more data to be added */ void tlsh_impl_final(TlshImpl *this, int fc_cons_option) { if (this->lsh_code_valid) { fprintf(stderr, "call to final() on a tlsh that is already valid\n"); return; } // incoming data must more than or equal to MIN_DATA_LENGTH bytes if (((fc_cons_option & TLSH_OPTION_CONSERVATIVE) == 0) && (this->data_len < MIN_DATA_LENGTH)) { // this->lsh_code be empty free(this->a_bucket); this->a_bucket = NULL; return; } if ((fc_cons_option & TLSH_OPTION_CONSERVATIVE) && (this->data_len < MIN_CONSERVATIVE_DATA_LENGTH)) { // this->lsh_code be empty free(this->a_bucket); this->a_bucket = NULL; return; } unsigned int q1, q2, q3; find_quartile(&q1, &q2, &q3, this->a_bucket); // issue #79 - divide by 0 if q3 == 0 if (q3 == 0) { free(this->a_bucket); this->a_bucket = NULL; return; } // buckets must be more than 50% non-zero int nonzero = 0; for (unsigned int i = 0; i < CODE_SIZE; i++) { for (unsigned int j = 0; j < 4; j++) { if (this->a_bucket[4 * i + j] > 0) { nonzero++; } } } #if defined BUCKETS_48 if (nonzero < 18) { // printf("nonzero=%d\n", nonzero); delete[] this->a_bucket; this->a_bucket = NULL; return; } #else if (nonzero <= 4 * CODE_SIZE / 2) { free(this->a_bucket); this->a_bucket = NULL; return; } #endif for (unsigned int i = 0; i < CODE_SIZE; i++) { unsigned char h = 0; for (unsigned int j = 0; j < 4; j++) { unsigned int k = this->a_bucket[4 * i + j]; if (q3 < k) { h += 3 << (j * 2); // leave the optimization j*2 = j<<1 or j*2 = j+j // for compiler } else if (q2 < k) { h += 2 << (j * 2); } else if (q1 < k) { h += 1 << (j * 2); } } this->lsh_bin.tmp_code[i] = h; } if ((fc_cons_option & TLSH_OPTION_KEEP_BUCKET) == 0) { // Done with a_bucket so deallocate free(this->a_bucket); this->a_bucket = NULL; } this->lsh_bin.lvalue = l_capturing(this->data_len); this->lsh_bin.Q.QR.q1ratio = (unsigned int) ((float) (q1 * 100) / (float) q3) % 16; this->lsh_bin.Q.QR.q2ratio = (unsigned int) ((float) (q2 * 100) / (float) q3) % 16; this->lsh_code_valid = true; } int tlsh_impl_from_tlsh_str(TlshImpl *impl, const char *str) { // Assume that we have 128 Buckets int start = 0; if (strncmp(str, "T1", 2) == 0) { start = 2; } else { start = 0; } // Validate input string for (int ii = 0; ii < INTERNAL_TLSH_STRING_LEN; ii++) { int i = ii + start; if (!((str[i] >= '0' && str[i] <= '9') || (str[i] >= 'A' && str[i] <= 'F') || (str[i] >= 'a' && str[i] <= 'f'))) { // printf("warning ii=%d str[%d]='%c'\n", ii, i, str[i]); return 1; } } int xi = INTERNAL_TLSH_STRING_LEN + start; if (((str[xi] >= '0' && str[xi] <= '9') || (str[xi] >= 'A' && str[xi] <= 'F') || (str[xi] >= 'a' && str[xi] <= 'f'))) { // printf("warning xi=%d\n", xi); return 1; } tlsh_impl_reset(impl); LshBinStruct tmp; from_hex(&str[start], INTERNAL_TLSH_STRING_LEN, (unsigned char *) &tmp); // Reconstruct checksum, Qrations & lvalue for (int k = 0; k < TLSH_CHECKSUM_LEN; k++) { impl->lsh_bin.checksum[k] = swap_byte(tmp.checksum[k]); } impl->lsh_bin.lvalue = swap_byte(tmp.lvalue); impl->lsh_bin.Q.qb = swap_byte(tmp.Q.qb); for (int i = 0; i < CODE_SIZE; i++) { impl->lsh_bin.tmp_code[i] = (tmp.tmp_code[CODE_SIZE - 1 - i]); } impl->lsh_code_valid = true; return 0; } const char *hash2( TlshImpl *impl, char *buffer, unsigned int bufSize, bool showvers) { if (bufSize < TLSH_STRING_LEN_REQ + 1) { strncpy(buffer, "", bufSize); return buffer; } if (impl->lsh_code_valid == false) { strncpy(buffer, "", bufSize); return buffer; } LshBinStruct tmp; for (int k = 0; k < TLSH_CHECKSUM_LEN; k++) { tmp.checksum[k] = swap_byte(impl->lsh_bin.checksum[k]); } tmp.lvalue = swap_byte(impl->lsh_bin.lvalue); tmp.Q.qb = swap_byte(impl->lsh_bin.Q.qb); for (int i = 0; i < CODE_SIZE; i++) { tmp.tmp_code[i] = (impl->lsh_bin.tmp_code[CODE_SIZE - 1 - i]); } if (showvers) { buffer[0] = 'T'; buffer[1] = '0' + showvers; to_hex((unsigned char *) &tmp, sizeof(tmp), &buffer[2]); } else { to_hex((unsigned char *) &tmp, sizeof(tmp), buffer); } return buffer; } /* to get the hex-encoded hash code */ const char *tlsh_impl_hash(TlshImpl *impl, bool showvers) { if (impl->lsh_code != NULL) { // lsh_code has been previously calculated, so just return it return impl->lsh_code; } impl->lsh_code = (char *) malloc(TLSH_STRING_LEN_REQ + 1); if (!impl->lsh_code) { return NULL; } memset(impl->lsh_code, 0, TLSH_STRING_LEN_REQ + 1); return hash2(impl, impl->lsh_code, TLSH_STRING_LEN_REQ + 1, showvers); } int tlsh_impl_compare(TlshImpl *this, TlshImpl *other) { return (memcmp(&(this->lsh_bin), &(other->lsh_bin), sizeof(this->lsh_bin))); } //////////////////////////////////////////// // the default for these parameters is 12 //////////////////////////////////////////// static int length_mult = 12; static int qratio_mult = 12; #ifdef TLSH_DISTANCE_PARAMETERS int hist_diff1_add = 1; int hist_diff2_add = 2; int hist_diff3_add = 6; void set_tlsh_distance_parameters( int length_mult_value, int qratio_mult_value, int hist_diff1_add_value, int hist_diff2_add_value, int hist_diff3_add_value) { if (length_mult_value != -1) { length_mult = length_mult_value; } if (qratio_mult_value != -1) { qratio_mult = qratio_mult_value; } if (hist_diff1_add_value != -1) { hist_diff1_add = hist_diff1_add_value; } if (hist_diff2_add_value != -1) { hist_diff2_add = hist_diff2_add_value; } if (hist_diff3_add_value != -1) { hist_diff3_add = hist_diff3_add_value; } } #endif int tlsh_impl_lvalue(TlshImpl *impl) { return (impl->lsh_bin.lvalue); } int tlsh_impl_q1ratio(TlshImpl *impl) { return (impl->lsh_bin.Q.QR.q1ratio); } int tlsh_impl_q2ratio(TlshImpl *impl) { return (impl->lsh_bin.Q.QR.q2ratio); } int tlsh_impl_is_valid(TlshImpl *impl) { return (impl->lsh_code_valid); } int tlsh_impl_checksum(TlshImpl *impl, int k) { if ((k >= TLSH_CHECKSUM_LEN) || (k < 0)) { return 0; } return impl->lsh_bin.checksum[k]; } int tlsh_impl_bucket_value(TlshImpl *impl, int bucket) { int idx; int elem; unsigned char bv; idx = (CODE_SIZE - (bucket / 4)) - 1; elem = bucket % 4; bv = impl->lsh_bin.tmp_code[idx]; int h1 = bv / 16; int h2 = bv % 16; int p1 = h1 / 4; int p2 = h1 % 4; int p3 = h2 / 4; int p4 = h2 % 4; if (elem == 0) { return (p1); } if (elem == 1) { return (p2); } if (elem == 2) { return (p3); } return (p4); } int tlsh_impl_histogram_count(TlshImpl *impl, int bucket) { if (impl->a_bucket == NULL) return (-1); return (impl->a_bucket[EFF_BUCKETS - 1 - bucket]); } int tlsh_impl_total_diff(TlshImpl *impl, TlshImpl *other, bool len_diff) { int diff = 0; if (len_diff) { int ldiff = mod_diff( impl->lsh_bin.lvalue, other->lsh_bin.lvalue, RANGE_LVALUE); if (ldiff == 0) diff = 0; else if (ldiff == 1) diff = 1; else diff += ldiff * length_mult; } int q1diff = mod_diff( impl->lsh_bin.Q.QR.q1ratio, other->lsh_bin.Q.QR.q1ratio, RANGE_QRATIO); if (q1diff <= 1) diff += q1diff; else diff += (q1diff - 1) * qratio_mult; int q2diff = mod_diff( impl->lsh_bin.Q.QR.q2ratio, other->lsh_bin.Q.QR.q2ratio, RANGE_QRATIO); if (q2diff <= 1) diff += q2diff; else diff += (q2diff - 1) * qratio_mult; for (int k = 0; k < TLSH_CHECKSUM_LEN; k++) { if (impl->lsh_bin.checksum[k] != other->lsh_bin.checksum[k]) { diff++; break; } } diff += h_distance( CODE_SIZE, impl->lsh_bin.tmp_code, other->lsh_bin.tmp_code); return (diff); } #define SWAP_UINT(x, y) \ do \ { \ unsigned int int_tmp = (x); \ (x) = (y); \ (y) = int_tmp; \ } while (0) void find_quartile( unsigned int *q1, unsigned int *q2, unsigned int *q3, const unsigned int *a_bucket) { unsigned int bucket_copy[EFF_BUCKETS], short_cut_left[EFF_BUCKETS], short_cut_right[EFF_BUCKETS], spl = 0, spr = 0; unsigned int p1 = EFF_BUCKETS / 4 - 1; unsigned int p2 = EFF_BUCKETS / 2 - 1; unsigned int p3 = EFF_BUCKETS - EFF_BUCKETS / 4 - 1; unsigned int end = EFF_BUCKETS - 1; for (unsigned int i = 0; i <= end; i++) { bucket_copy[i] = a_bucket[i]; } for (unsigned int l = 0, r = end;;) { unsigned int ret = partition(bucket_copy, l, r); if (ret > p2) { r = ret - 1; short_cut_right[spr] = ret; spr++; } else if (ret < p2) { l = ret + 1; short_cut_left[spl] = ret; spl++; } else { *q2 = bucket_copy[p2]; break; } } short_cut_left[spl] = p2 - 1; short_cut_right[spr] = p2 + 1; for (unsigned int i = 0, l = 0; i <= spl; i++) { unsigned int r = short_cut_left[i]; if (r > p1) { for (;;) { unsigned int ret = partition(bucket_copy, l, r); if (ret > p1) { r = ret - 1; } else if (ret < p1) { l = ret + 1; } else { *q1 = bucket_copy[p1]; break; } } break; } else if (r < p1) { l = r; } else { *q1 = bucket_copy[p1]; break; } } for (unsigned int i = 0, r = end; i <= spr; i++) { unsigned int l = short_cut_right[i]; if (l < p3) { for (;;) { unsigned int ret = partition(bucket_copy, l, r); if (ret > p3) { r = ret - 1; } else if (ret < p3) { l = ret + 1; } else { *q3 = bucket_copy[p3]; break; } } break; } else if (l > p3) { r = l; } else { *q3 = bucket_copy[p3]; break; } } } unsigned int partition(unsigned int *buf, unsigned int left, unsigned int right) { if (left == right) { return left; } if (left + 1 == right) { if (buf[left] > buf[right]) { SWAP_UINT(buf[left], buf[right]); } return left; } unsigned int ret = left, pivot = (left + right) >> 1; unsigned int val = buf[pivot]; buf[pivot] = buf[right]; buf[right] = val; for (unsigned int i = left; i < right; i++) { if (buf[i] < val) { SWAP_UINT(buf[ret], buf[i]); ret++; } } buf[right] = buf[ret]; buf[ret] = val; return ret; } yara-4.5.3/libyara/tlshc/tlsh_impl.h000066400000000000000000000062211501365277300173750ustar00rootroot00000000000000#ifndef __TLSH_TLSH_IMPL_H__ #define __TLSH_TLSH_IMPL_H__ #include #define SLIDING_WND_SIZE 5 #define BUCKETS 256 #define Q_BITS 2 // 2 bits; quartile value 0, 1, 2, 3 // BUCKETS_256 & CHECKSUM_3B are compiler switches defined in CMakeLists.txt #if defined BUCKETS_256 #define EFF_BUCKETS 256 #define CODE_SIZE 64 // 256 * 2 bits = 64 bytes #if defined CHECKSUM_3B #define INTERNAL_TLSH_STRING_LEN 138 #define TLSH_CHECKSUM_LEN 3 // defined in tlsh.h #define TLSH_STRING_LEN 138 // 2 + 3 + 64 bytes = 138 // hexidecimal chars #else #define INTERNAL_TLSH_STRING_LEN 134 #define TLSH_CHECKSUM_LEN 1 // defined in tlsh.h #define TLSH_STRING_LEN 134 // 2 + 1 + 64 bytes = 134 // hexidecimal chars #endif #endif #if defined BUCKETS_128 #define EFF_BUCKETS 128 #define CODE_SIZE 32 // 128 * 2 bits = 32 bytes #if defined CHECKSUM_3B #define INTERNAL_TLSH_STRING_LEN 74 #define TLSH_CHECKSUM_LEN 3 // defined in tlsh.h #define TLSH_STRING_LEN 74 // 2 + 3 + 32 bytes = 74 // hexidecimal chars #else #define INTERNAL_TLSH_STRING_LEN 70 #define TLSH_CHECKSUM_LEN 1 // defined in tlsh.h #define TLSH_STRING_LEN 70 // 2 + 1 + 32 bytes = 70 // hexidecimal chars #endif #endif #if defined BUCKETS_48 #define INTERNAL_TLSH_STRING_LEN 33 #define EFF_BUCKETS 48 #define CODE_SIZE 12 // 48 * 2 bits = 12 bytes #define TLSH_CHECKSUM_LEN 1 // defined in tlsh.h #define TLSH_STRING_LEN 30 // 2 + 1 + 12 bytes = 30 // hexidecimal chars #endif #ifdef __cplusplus extern "C" { #endif #pragma pack(push) #pragma pack(1) typedef struct { unsigned char checksum[TLSH_CHECKSUM_LEN]; unsigned char lvalue; union { unsigned char qb; struct { #if defined(WORDS_BIGENDIAN) unsigned char q2ratio : 4; unsigned char q1ratio : 4; #else unsigned char q1ratio : 4; unsigned char q2ratio : 4; #endif } QR; } Q; unsigned char tmp_code[CODE_SIZE]; } LshBinStruct; #pragma pack(pop) typedef struct TlshImpl { unsigned int *a_bucket; unsigned char slide_window[SLIDING_WND_SIZE]; unsigned int data_len; LshBinStruct lsh_bin; char *lsh_code; bool lsh_code_valid; } TlshImpl; TlshImpl *tlsh_impl_new(); void tlsh_impl_free(TlshImpl *impl); int tlsh_impl_update( TlshImpl *impl, const unsigned char *data, unsigned int len, int tlsh_option); void tlsh_impl_final(TlshImpl *impl, int fc_cons_option); void tlsh_impl_reset(TlshImpl *impl); int tlsh_impl_is_valid(TlshImpl *impl); int tlsh_impl_compare(TlshImpl *impl, TlshImpl *other); int tlsh_impl_total_diff(TlshImpl *impl, TlshImpl *other, bool len_diff); int tlsh_impl_lvalue(TlshImpl *impl); int tlsh_impl_q1ratio(TlshImpl *impl); int tlsh_impl_q2ratio(TlshImpl *impl); int tlsh_impl_checksum(TlshImpl *impl, int k); int tlsh_impl_bucket_value(TlshImpl *impl, int bucket); int tlsh_impl_histogram_count(TlshImpl *impl, int bucket); int tlsh_impl_from_tlsh_str(TlshImpl *impl, const char *str); const char *tlsh_impl_hash(TlshImpl *impl, bool showvers); #ifdef __cplusplus } #endif #endif // __TLSH_TLSH_IMPL_H__yara-4.5.3/libyara/tlshc/tlsh_util.c000066400000000000000000010241761501365277300174160ustar00rootroot00000000000000#include static unsigned char bit_pairs_diff_table[][256] = { {0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 6, 7, 8, 12, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 12, 13, 14, 18, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 10, 11, 12, 16, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 14, 15, 16, 20, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 12, 13, 14, 18, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 14, 15, 16, 20, 12, 13, 14, 18, 13, 14, 15, 19, 14, 15, 16, 20, 18, 19, 20, 24}, {1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 7, 6, 7, 8, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 13, 12, 13, 14, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 11, 10, 11, 12, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 15, 14, 15, 16, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 13, 12, 13, 14, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 15, 14, 15, 16, 13, 12, 13, 14, 14, 13, 14, 15, 15, 14, 15, 16, 19, 18, 19, 20}, {2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 8, 7, 6, 7, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 14, 13, 12, 13, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 12, 11, 10, 11, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 16, 15, 14, 15, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 14, 13, 12, 13, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 16, 15, 14, 15, 14, 13, 12, 13, 15, 14, 13, 14, 16, 15, 14, 15, 20, 19, 18, 19}, {6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 12, 8, 7, 6, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 18, 14, 13, 12, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 16, 12, 11, 10, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 20, 16, 15, 14, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 18, 14, 13, 12, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 20, 16, 15, 14, 18, 14, 13, 12, 19, 15, 14, 13, 20, 16, 15, 14, 24, 20, 19, 18}, {1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 13, 14, 15, 19, 12, 13, 14, 18, 13, 14, 15, 19, 14, 15, 16, 20}, {2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 14, 13, 14, 15, 13, 12, 13, 14, 14, 13, 14, 15, 15, 14, 15, 16}, {3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 15, 14, 13, 14, 14, 13, 12, 13, 15, 14, 13, 14, 16, 15, 14, 15}, {7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 19, 15, 14, 13, 18, 14, 13, 12, 19, 15, 14, 13, 20, 16, 15, 14}, {2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 14, 15, 16, 20, 13, 14, 15, 19, 12, 13, 14, 18, 13, 14, 15, 19}, {3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 15, 14, 15, 16, 14, 13, 14, 15, 13, 12, 13, 14, 14, 13, 14, 15}, {4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 16, 15, 14, 15, 15, 14, 13, 14, 14, 13, 12, 13, 15, 14, 13, 14}, {8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 20, 16, 15, 14, 19, 15, 14, 13, 18, 14, 13, 12, 19, 15, 14, 13}, {6, 7, 8, 12, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 12, 13, 14, 18, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 10, 11, 12, 16, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 14, 15, 16, 20, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 12, 13, 14, 18, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 14, 15, 16, 20, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 18, 19, 20, 24, 14, 15, 16, 20, 13, 14, 15, 19, 12, 13, 14, 18}, {7, 6, 7, 8, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 13, 12, 13, 14, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 11, 10, 11, 12, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 15, 14, 15, 16, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 13, 12, 13, 14, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 15, 14, 15, 16, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 19, 18, 19, 20, 15, 14, 15, 16, 14, 13, 14, 15, 13, 12, 13, 14}, {8, 7, 6, 7, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 14, 13, 12, 13, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 12, 11, 10, 11, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 16, 15, 14, 15, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 14, 13, 12, 13, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 16, 15, 14, 15, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 20, 19, 18, 19, 16, 15, 14, 15, 15, 14, 13, 14, 14, 13, 12, 13}, {12, 8, 7, 6, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 18, 14, 13, 12, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 16, 12, 11, 10, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 20, 16, 15, 14, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 18, 14, 13, 12, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 20, 16, 15, 14, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 24, 20, 19, 18, 20, 16, 15, 14, 19, 15, 14, 13, 18, 14, 13, 12}, {1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 6, 7, 8, 12, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 10, 11, 12, 16, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 12, 13, 14, 18, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 14, 15, 16, 20}, {2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 7, 6, 7, 8, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 11, 10, 11, 12, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 13, 12, 13, 14, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 15, 14, 15, 16}, {3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 8, 7, 6, 7, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 12, 11, 10, 11, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 14, 13, 12, 13, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 16, 15, 14, 15}, {7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 12, 8, 7, 6, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 16, 12, 11, 10, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 18, 14, 13, 12, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 20, 16, 15, 14}, {2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16}, {3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12}, {4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11}, {8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10}, {3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15}, {4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11}, {5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10}, {9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9}, {7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 6, 7, 8, 12, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 10, 11, 12, 16, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 12, 13, 14, 18, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 14, 15, 16, 20, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14}, {8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 7, 6, 7, 8, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 11, 10, 11, 12, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 13, 12, 13, 14, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 15, 14, 15, 16, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10}, {9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 8, 7, 6, 7, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 12, 11, 10, 11, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 14, 13, 12, 13, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 16, 15, 14, 15, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9}, {13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 12, 8, 7, 6, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 16, 12, 11, 10, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 18, 14, 13, 12, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 20, 16, 15, 14, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8}, {2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 6, 7, 8, 12, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 10, 11, 12, 16, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 14, 15, 16, 20, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 12, 13, 14, 18, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19}, {3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 7, 6, 7, 8, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 11, 10, 11, 12, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 15, 14, 15, 16, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 13, 12, 13, 14, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15}, {4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 8, 7, 6, 7, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 12, 11, 10, 11, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 16, 15, 14, 15, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 14, 13, 12, 13, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14}, {8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 12, 8, 7, 6, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 16, 12, 11, 10, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 20, 16, 15, 14, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 18, 14, 13, 12, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13}, {3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15}, {4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11}, {5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10}, {9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9}, {4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14}, {5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10}, {6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9}, {10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8}, {8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 6, 7, 8, 12, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 10, 11, 12, 16, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 14, 15, 16, 20, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 12, 13, 14, 18, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13}, {9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 7, 6, 7, 8, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 11, 10, 11, 12, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 15, 14, 15, 16, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 13, 12, 13, 14, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9}, {10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 8, 7, 6, 7, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 12, 11, 10, 11, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 16, 15, 14, 15, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 14, 13, 12, 13, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8}, {14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 12, 8, 7, 6, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 16, 12, 11, 10, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 20, 16, 15, 14, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 18, 14, 13, 12, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7}, {6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 12, 13, 14, 18, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 14, 15, 16, 20, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 10, 11, 12, 16, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 12, 13, 14, 18, 13, 14, 15, 19, 14, 15, 16, 20, 18, 19, 20, 24, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 14, 15, 16, 20, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 12, 13, 14, 18}, {7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 13, 12, 13, 14, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 15, 14, 15, 16, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 11, 10, 11, 12, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 13, 12, 13, 14, 14, 13, 14, 15, 15, 14, 15, 16, 19, 18, 19, 20, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 15, 14, 15, 16, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 13, 12, 13, 14}, {8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 14, 13, 12, 13, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 16, 15, 14, 15, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 12, 11, 10, 11, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 14, 13, 12, 13, 15, 14, 13, 14, 16, 15, 14, 15, 20, 19, 18, 19, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 16, 15, 14, 15, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 14, 13, 12, 13}, {12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 18, 14, 13, 12, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 20, 16, 15, 14, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 16, 12, 11, 10, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 18, 14, 13, 12, 19, 15, 14, 13, 20, 16, 15, 14, 24, 20, 19, 18, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 20, 16, 15, 14, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 18, 14, 13, 12}, {7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 13, 14, 15, 19, 12, 13, 14, 18, 13, 14, 15, 19, 14, 15, 16, 20, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14}, {8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 14, 13, 14, 15, 13, 12, 13, 14, 14, 13, 14, 15, 15, 14, 15, 16, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10}, {9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 15, 14, 13, 14, 14, 13, 12, 13, 15, 14, 13, 14, 16, 15, 14, 15, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9}, {13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 19, 15, 14, 13, 18, 14, 13, 12, 19, 15, 14, 13, 20, 16, 15, 14, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8}, {8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 14, 15, 16, 20, 13, 14, 15, 19, 12, 13, 14, 18, 13, 14, 15, 19, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13}, {9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 15, 14, 15, 16, 14, 13, 14, 15, 13, 12, 13, 14, 14, 13, 14, 15, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9}, {10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 16, 15, 14, 15, 15, 14, 13, 14, 14, 13, 12, 13, 15, 14, 13, 14, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8}, {14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 20, 16, 15, 14, 19, 15, 14, 13, 18, 14, 13, 12, 19, 15, 14, 13, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7}, {12, 13, 14, 18, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 6, 7, 8, 12, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 14, 15, 16, 20, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 10, 11, 12, 16, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 18, 19, 20, 24, 14, 15, 16, 20, 13, 14, 15, 19, 12, 13, 14, 18, 14, 15, 16, 20, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 12, 13, 14, 18, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12}, {13, 12, 13, 14, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 7, 6, 7, 8, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 15, 14, 15, 16, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 11, 10, 11, 12, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 19, 18, 19, 20, 15, 14, 15, 16, 14, 13, 14, 15, 13, 12, 13, 14, 15, 14, 15, 16, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 13, 12, 13, 14, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8}, {14, 13, 12, 13, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 8, 7, 6, 7, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 16, 15, 14, 15, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 12, 11, 10, 11, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 20, 19, 18, 19, 16, 15, 14, 15, 15, 14, 13, 14, 14, 13, 12, 13, 16, 15, 14, 15, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 14, 13, 12, 13, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7}, {18, 14, 13, 12, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 12, 8, 7, 6, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 20, 16, 15, 14, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 16, 12, 11, 10, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 24, 20, 19, 18, 20, 16, 15, 14, 19, 15, 14, 13, 18, 14, 13, 12, 20, 16, 15, 14, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 18, 14, 13, 12, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6}, {1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 6, 7, 8, 12, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 12, 13, 14, 18, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 10, 11, 12, 16, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 14, 15, 16, 20}, {2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 7, 6, 7, 8, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 13, 12, 13, 14, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 11, 10, 11, 12, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 15, 14, 15, 16}, {3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 8, 7, 6, 7, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 14, 13, 12, 13, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 12, 11, 10, 11, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 16, 15, 14, 15}, {7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 12, 8, 7, 6, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 18, 14, 13, 12, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 16, 12, 11, 10, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 20, 16, 15, 14}, {2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16}, {3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12}, {4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11}, {8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10}, {3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15}, {4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11}, {5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10}, {9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9}, {7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 12, 13, 14, 18, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 10, 11, 12, 16, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 14, 15, 16, 20, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14}, {8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 13, 12, 13, 14, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 11, 10, 11, 12, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 15, 14, 15, 16, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10}, {9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 14, 13, 12, 13, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 12, 11, 10, 11, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 16, 15, 14, 15, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9}, {13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 18, 14, 13, 12, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 16, 12, 11, 10, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 20, 16, 15, 14, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8}, {2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 6, 7, 8, 12, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 10, 11, 12, 16}, {3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 7, 6, 7, 8, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 11, 10, 11, 12}, {4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 8, 7, 6, 7, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 12, 11, 10, 11}, {8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 12, 8, 7, 6, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 16, 12, 11, 10}, {3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12}, {4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8}, {5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7}, {9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6}, {4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11}, {5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7}, {6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6}, {10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5}, {8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 6, 7, 8, 12, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 10, 11, 12, 16, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10}, {9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 7, 6, 7, 8, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 11, 10, 11, 12, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6}, {10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 8, 7, 6, 7, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 12, 11, 10, 11, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5}, {14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 12, 8, 7, 6, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 16, 12, 11, 10, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4}, {3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 6, 7, 8, 12, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 10, 11, 12, 16, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15}, {4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 7, 6, 7, 8, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 11, 10, 11, 12, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11}, {5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 8, 7, 6, 7, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 12, 11, 10, 11, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10}, {9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 12, 8, 7, 6, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 16, 12, 11, 10, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9}, {4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11}, {5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7}, {6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6}, {10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5}, {5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10}, {6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6}, {7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5}, {11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4}, {9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 6, 7, 8, 12, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 10, 11, 12, 16, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9}, {10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 7, 6, 7, 8, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 11, 10, 11, 12, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5}, {11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 8, 7, 6, 7, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 12, 11, 10, 11, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4}, {15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 12, 8, 7, 6, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 16, 12, 11, 10, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3}, {7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 12, 13, 14, 18, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 14, 15, 16, 20, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 10, 11, 12, 16, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14}, {8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 13, 12, 13, 14, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 15, 14, 15, 16, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 11, 10, 11, 12, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10}, {9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 14, 13, 12, 13, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 16, 15, 14, 15, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 12, 11, 10, 11, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9}, {13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 18, 14, 13, 12, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 20, 16, 15, 14, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 16, 12, 11, 10, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8}, {8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10}, {9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6}, {10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5}, {14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4}, {9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9}, {10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5}, {11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4}, {15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3}, {13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 12, 13, 14, 18, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 6, 7, 8, 12, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 14, 15, 16, 20, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 10, 11, 12, 16, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8}, {14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 13, 12, 13, 14, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 7, 6, 7, 8, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 15, 14, 15, 16, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 11, 10, 11, 12, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4}, {15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 14, 13, 12, 13, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 8, 7, 6, 7, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 16, 15, 14, 15, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 12, 11, 10, 11, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3}, {19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 18, 14, 13, 12, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 12, 8, 7, 6, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 20, 16, 15, 14, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 16, 12, 11, 10, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2}, {2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 10, 11, 12, 16, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 14, 15, 16, 20, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 6, 7, 8, 12, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 12, 13, 14, 18, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19}, {3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 11, 10, 11, 12, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 15, 14, 15, 16, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 7, 6, 7, 8, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 13, 12, 13, 14, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15}, {4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 12, 11, 10, 11, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 16, 15, 14, 15, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 8, 7, 6, 7, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 14, 13, 12, 13, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14}, {8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 16, 12, 11, 10, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 20, 16, 15, 14, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 12, 8, 7, 6, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 18, 14, 13, 12, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13}, {3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15}, {4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11}, {5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10}, {9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9}, {4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14}, {5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10}, {6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9}, {10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8}, {8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 10, 11, 12, 16, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 14, 15, 16, 20, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 12, 13, 14, 18, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13}, {9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 11, 10, 11, 12, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 15, 14, 15, 16, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 13, 12, 13, 14, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9}, {10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 12, 11, 10, 11, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 16, 15, 14, 15, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 14, 13, 12, 13, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8}, {14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 16, 12, 11, 10, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 20, 16, 15, 14, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 18, 14, 13, 12, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7}, {3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 10, 11, 12, 16, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 6, 7, 8, 12, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15}, {4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 11, 10, 11, 12, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 7, 6, 7, 8, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11}, {5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 12, 11, 10, 11, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 8, 7, 6, 7, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10}, {9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 16, 12, 11, 10, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 12, 8, 7, 6, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9}, {4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11}, {5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7}, {6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6}, {10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5}, {5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10}, {6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6}, {7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5}, {11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4}, {9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 10, 11, 12, 16, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 6, 7, 8, 12, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9}, {10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 11, 10, 11, 12, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 7, 6, 7, 8, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5}, {11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 12, 11, 10, 11, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 8, 7, 6, 7, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4}, {15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 16, 12, 11, 10, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 12, 8, 7, 6, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3}, {4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 10, 11, 12, 16, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 6, 7, 8, 12, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14}, {5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 11, 10, 11, 12, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 7, 6, 7, 8, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10}, {6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 12, 11, 10, 11, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 8, 7, 6, 7, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9}, {10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 16, 12, 11, 10, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 12, 8, 7, 6, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8}, {5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10}, {6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6}, {7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5}, {11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4}, {6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9}, {7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5}, {8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4}, {12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3}, {10, 11, 12, 16, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 6, 7, 8, 12, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8}, {11, 10, 11, 12, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 7, 6, 7, 8, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4}, {12, 11, 10, 11, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 8, 7, 6, 7, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3}, {16, 12, 11, 10, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 12, 8, 7, 6, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2}, {8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 14, 15, 16, 20, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 10, 11, 12, 16, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 12, 13, 14, 18, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13}, {9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 15, 14, 15, 16, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 11, 10, 11, 12, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 13, 12, 13, 14, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9}, {10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 16, 15, 14, 15, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 12, 11, 10, 11, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 14, 13, 12, 13, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8}, {14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 20, 16, 15, 14, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 16, 12, 11, 10, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 18, 14, 13, 12, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7}, {9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9}, {10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5}, {11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4}, {15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3}, {10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8}, {11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4}, {12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3}, {16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2}, {14, 15, 16, 20, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 10, 11, 12, 16, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 12, 13, 14, 18, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 6, 7, 8, 12, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7}, {15, 14, 15, 16, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 11, 10, 11, 12, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 13, 12, 13, 14, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 7, 6, 7, 8, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3}, {16, 15, 14, 15, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 12, 11, 10, 11, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 14, 13, 12, 13, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 8, 7, 6, 7, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2}, {20, 16, 15, 14, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 16, 12, 11, 10, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 18, 14, 13, 12, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 12, 8, 7, 6, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1}, {6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 12, 13, 14, 18, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 14, 15, 16, 20, 12, 13, 14, 18, 13, 14, 15, 19, 14, 15, 16, 20, 18, 19, 20, 24, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 10, 11, 12, 16, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 14, 15, 16, 20, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 6, 7, 8, 12, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 12, 13, 14, 18}, {7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 13, 12, 13, 14, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 15, 14, 15, 16, 13, 12, 13, 14, 14, 13, 14, 15, 15, 14, 15, 16, 19, 18, 19, 20, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 11, 10, 11, 12, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 15, 14, 15, 16, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 7, 6, 7, 8, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 13, 12, 13, 14}, {8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 14, 13, 12, 13, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 16, 15, 14, 15, 14, 13, 12, 13, 15, 14, 13, 14, 16, 15, 14, 15, 20, 19, 18, 19, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 12, 11, 10, 11, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 16, 15, 14, 15, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 8, 7, 6, 7, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 14, 13, 12, 13}, {12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 18, 14, 13, 12, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 20, 16, 15, 14, 18, 14, 13, 12, 19, 15, 14, 13, 20, 16, 15, 14, 24, 20, 19, 18, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 16, 12, 11, 10, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 20, 16, 15, 14, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 12, 8, 7, 6, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 18, 14, 13, 12}, {7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 13, 14, 15, 19, 12, 13, 14, 18, 13, 14, 15, 19, 14, 15, 16, 20, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14}, {8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 14, 13, 14, 15, 13, 12, 13, 14, 14, 13, 14, 15, 15, 14, 15, 16, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10}, {9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 15, 14, 13, 14, 14, 13, 12, 13, 15, 14, 13, 14, 16, 15, 14, 15, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9}, {13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 19, 15, 14, 13, 18, 14, 13, 12, 19, 15, 14, 13, 20, 16, 15, 14, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8}, {8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 14, 15, 16, 20, 13, 14, 15, 19, 12, 13, 14, 18, 13, 14, 15, 19, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13}, {9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 15, 14, 15, 16, 14, 13, 14, 15, 13, 12, 13, 14, 14, 13, 14, 15, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9}, {10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 16, 15, 14, 15, 15, 14, 13, 14, 14, 13, 12, 13, 15, 14, 13, 14, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8}, {14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 20, 16, 15, 14, 19, 15, 14, 13, 18, 14, 13, 12, 19, 15, 14, 13, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7}, {12, 13, 14, 18, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 14, 15, 16, 20, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 18, 19, 20, 24, 14, 15, 16, 20, 13, 14, 15, 19, 12, 13, 14, 18, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 10, 11, 12, 16, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 14, 15, 16, 20, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 12, 13, 14, 18, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12}, {13, 12, 13, 14, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 15, 14, 15, 16, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 19, 18, 19, 20, 15, 14, 15, 16, 14, 13, 14, 15, 13, 12, 13, 14, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 11, 10, 11, 12, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 15, 14, 15, 16, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 13, 12, 13, 14, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8}, {14, 13, 12, 13, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 16, 15, 14, 15, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 20, 19, 18, 19, 16, 15, 14, 15, 15, 14, 13, 14, 14, 13, 12, 13, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 12, 11, 10, 11, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 16, 15, 14, 15, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 14, 13, 12, 13, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7}, {18, 14, 13, 12, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 20, 16, 15, 14, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 24, 20, 19, 18, 20, 16, 15, 14, 19, 15, 14, 13, 18, 14, 13, 12, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 16, 12, 11, 10, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 20, 16, 15, 14, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 18, 14, 13, 12, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6}, {7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 12, 13, 14, 18, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 14, 15, 16, 20, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 10, 11, 12, 16, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 6, 7, 8, 12, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14}, {8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 13, 12, 13, 14, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 15, 14, 15, 16, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 11, 10, 11, 12, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 7, 6, 7, 8, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10}, {9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 14, 13, 12, 13, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 16, 15, 14, 15, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 12, 11, 10, 11, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 8, 7, 6, 7, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9}, {13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 18, 14, 13, 12, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 20, 16, 15, 14, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 16, 12, 11, 10, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 12, 8, 7, 6, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8}, {8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10}, {9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6}, {10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5}, {14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4}, {9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9}, {10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5}, {11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4}, {15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3}, {13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 12, 13, 14, 18, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 14, 15, 16, 20, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 10, 11, 12, 16, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 6, 7, 8, 12, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8}, {14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 13, 12, 13, 14, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 15, 14, 15, 16, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 11, 10, 11, 12, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 7, 6, 7, 8, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4}, {15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 14, 13, 12, 13, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 16, 15, 14, 15, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 12, 11, 10, 11, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 8, 7, 6, 7, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3}, {19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 18, 14, 13, 12, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 20, 16, 15, 14, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 16, 12, 11, 10, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 12, 8, 7, 6, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2}, {8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 14, 15, 16, 20, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 12, 13, 14, 18, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 10, 11, 12, 16, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 6, 7, 8, 12, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13}, {9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 15, 14, 15, 16, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 13, 12, 13, 14, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 11, 10, 11, 12, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 7, 6, 7, 8, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9}, {10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 16, 15, 14, 15, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 14, 13, 12, 13, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 12, 11, 10, 11, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 8, 7, 6, 7, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8}, {14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 20, 16, 15, 14, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 18, 14, 13, 12, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 16, 12, 11, 10, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 12, 8, 7, 6, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7}, {9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9}, {10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5}, {11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4}, {15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3}, {10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8}, {11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4}, {12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3}, {16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2}, {14, 15, 16, 20, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 12, 13, 14, 18, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 10, 11, 12, 16, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 6, 7, 8, 12, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7}, {15, 14, 15, 16, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 13, 12, 13, 14, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 11, 10, 11, 12, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 7, 6, 7, 8, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3}, {16, 15, 14, 15, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 14, 13, 12, 13, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 12, 11, 10, 11, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 8, 7, 6, 7, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2}, {20, 16, 15, 14, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 18, 14, 13, 12, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 16, 12, 11, 10, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 12, 8, 7, 6, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1}, {12, 13, 14, 18, 13, 14, 15, 19, 14, 15, 16, 20, 18, 19, 20, 24, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 14, 15, 16, 20, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 12, 13, 14, 18, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 14, 15, 16, 20, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 10, 11, 12, 16, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 13, 14, 15, 19, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 9, 10, 11, 15, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 12, 13, 14, 18, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8, 6, 7, 8, 12}, {13, 12, 13, 14, 14, 13, 14, 15, 15, 14, 15, 16, 19, 18, 19, 20, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 15, 14, 15, 16, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 13, 12, 13, 14, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 15, 14, 15, 16, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 11, 10, 11, 12, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 14, 13, 14, 15, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 10, 9, 10, 11, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 13, 12, 13, 14, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4, 7, 6, 7, 8}, {14, 13, 12, 13, 15, 14, 13, 14, 16, 15, 14, 15, 20, 19, 18, 19, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 16, 15, 14, 15, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 14, 13, 12, 13, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 16, 15, 14, 15, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 12, 11, 10, 11, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 15, 14, 13, 14, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 11, 10, 9, 10, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 14, 13, 12, 13, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3, 8, 7, 6, 7}, {18, 14, 13, 12, 19, 15, 14, 13, 20, 16, 15, 14, 24, 20, 19, 18, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 20, 16, 15, 14, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 18, 14, 13, 12, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 20, 16, 15, 14, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 16, 12, 11, 10, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 19, 15, 14, 13, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 15, 11, 10, 9, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 18, 14, 13, 12, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2, 12, 8, 7, 6}, {13, 14, 15, 19, 12, 13, 14, 18, 13, 14, 15, 19, 14, 15, 16, 20, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 10, 11, 12, 16, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 6, 7, 8, 12, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 9, 10, 11, 15, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 5, 6, 7, 11, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 8, 9, 10, 14, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 4, 5, 6, 10, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 3, 4, 5, 9, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7, 2, 3, 4, 8}, {14, 13, 14, 15, 13, 12, 13, 14, 14, 13, 14, 15, 15, 14, 15, 16, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 11, 10, 11, 12, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 7, 6, 7, 8, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 10, 9, 10, 11, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 6, 5, 6, 7, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 9, 8, 9, 10, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 5, 4, 5, 6, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 4, 3, 4, 5, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3, 3, 2, 3, 4}, {15, 14, 13, 14, 14, 13, 12, 13, 15, 14, 13, 14, 16, 15, 14, 15, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 12, 11, 10, 11, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 8, 7, 6, 7, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 11, 10, 9, 10, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 7, 6, 5, 6, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 10, 9, 8, 9, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 6, 5, 4, 5, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 5, 4, 3, 4, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2, 4, 3, 2, 3}, {19, 15, 14, 13, 18, 14, 13, 12, 19, 15, 14, 13, 20, 16, 15, 14, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 16, 12, 11, 10, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 12, 8, 7, 6, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 15, 11, 10, 9, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 11, 7, 6, 5, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 14, 10, 9, 8, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 10, 6, 5, 4, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 9, 5, 4, 3, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1, 8, 4, 3, 2}, {14, 15, 16, 20, 13, 14, 15, 19, 12, 13, 14, 18, 13, 14, 15, 19, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 9, 10, 11, 15, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 5, 6, 7, 11, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 8, 9, 10, 14, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 4, 5, 6, 10, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 7, 8, 9, 13, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 3, 4, 5, 9, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 2, 3, 4, 8, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6, 1, 2, 3, 7}, {15, 14, 15, 16, 14, 13, 14, 15, 13, 12, 13, 14, 14, 13, 14, 15, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 10, 9, 10, 11, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 6, 5, 6, 7, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 9, 8, 9, 10, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 5, 4, 5, 6, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 8, 7, 8, 9, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 4, 3, 4, 5, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 3, 2, 3, 4, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2, 2, 1, 2, 3}, {16, 15, 14, 15, 15, 14, 13, 14, 14, 13, 12, 13, 15, 14, 13, 14, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 11, 10, 9, 10, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 7, 6, 5, 6, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 10, 9, 8, 9, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 6, 5, 4, 5, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 9, 8, 7, 8, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 5, 4, 3, 4, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 4, 3, 2, 3, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1, 3, 2, 1, 2}, {20, 16, 15, 14, 19, 15, 14, 13, 18, 14, 13, 12, 19, 15, 14, 13, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 15, 11, 10, 9, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 11, 7, 6, 5, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 14, 10, 9, 8, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 10, 6, 5, 4, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 13, 9, 8, 7, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 9, 5, 4, 3, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 8, 4, 3, 2, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0, 7, 3, 2, 1}, {18, 19, 20, 24, 14, 15, 16, 20, 13, 14, 15, 19, 12, 13, 14, 18, 14, 15, 16, 20, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 12, 13, 14, 18, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 14, 15, 16, 20, 10, 11, 12, 16, 9, 10, 11, 15, 8, 9, 10, 14, 10, 11, 12, 16, 6, 7, 8, 12, 5, 6, 7, 11, 4, 5, 6, 10, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 13, 14, 15, 19, 9, 10, 11, 15, 8, 9, 10, 14, 7, 8, 9, 13, 9, 10, 11, 15, 5, 6, 7, 11, 4, 5, 6, 10, 3, 4, 5, 9, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 12, 13, 14, 18, 8, 9, 10, 14, 7, 8, 9, 13, 6, 7, 8, 12, 8, 9, 10, 14, 4, 5, 6, 10, 3, 4, 5, 9, 2, 3, 4, 8, 7, 8, 9, 13, 3, 4, 5, 9, 2, 3, 4, 8, 1, 2, 3, 7, 6, 7, 8, 12, 2, 3, 4, 8, 1, 2, 3, 7, 0, 1, 2, 6}, {19, 18, 19, 20, 15, 14, 15, 16, 14, 13, 14, 15, 13, 12, 13, 14, 15, 14, 15, 16, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 13, 12, 13, 14, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 15, 14, 15, 16, 11, 10, 11, 12, 10, 9, 10, 11, 9, 8, 9, 10, 11, 10, 11, 12, 7, 6, 7, 8, 6, 5, 6, 7, 5, 4, 5, 6, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 14, 13, 14, 15, 10, 9, 10, 11, 9, 8, 9, 10, 8, 7, 8, 9, 10, 9, 10, 11, 6, 5, 6, 7, 5, 4, 5, 6, 4, 3, 4, 5, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 13, 12, 13, 14, 9, 8, 9, 10, 8, 7, 8, 9, 7, 6, 7, 8, 9, 8, 9, 10, 5, 4, 5, 6, 4, 3, 4, 5, 3, 2, 3, 4, 8, 7, 8, 9, 4, 3, 4, 5, 3, 2, 3, 4, 2, 1, 2, 3, 7, 6, 7, 8, 3, 2, 3, 4, 2, 1, 2, 3, 1, 0, 1, 2}, {20, 19, 18, 19, 16, 15, 14, 15, 15, 14, 13, 14, 14, 13, 12, 13, 16, 15, 14, 15, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 14, 13, 12, 13, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 16, 15, 14, 15, 12, 11, 10, 11, 11, 10, 9, 10, 10, 9, 8, 9, 12, 11, 10, 11, 8, 7, 6, 7, 7, 6, 5, 6, 6, 5, 4, 5, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 15, 14, 13, 14, 11, 10, 9, 10, 10, 9, 8, 9, 9, 8, 7, 8, 11, 10, 9, 10, 7, 6, 5, 6, 6, 5, 4, 5, 5, 4, 3, 4, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 14, 13, 12, 13, 10, 9, 8, 9, 9, 8, 7, 8, 8, 7, 6, 7, 10, 9, 8, 9, 6, 5, 4, 5, 5, 4, 3, 4, 4, 3, 2, 3, 9, 8, 7, 8, 5, 4, 3, 4, 4, 3, 2, 3, 3, 2, 1, 2, 8, 7, 6, 7, 4, 3, 2, 3, 3, 2, 1, 2, 2, 1, 0, 1}, {24, 20, 19, 18, 20, 16, 15, 14, 19, 15, 14, 13, 18, 14, 13, 12, 20, 16, 15, 14, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 18, 14, 13, 12, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 20, 16, 15, 14, 16, 12, 11, 10, 15, 11, 10, 9, 14, 10, 9, 8, 16, 12, 11, 10, 12, 8, 7, 6, 11, 7, 6, 5, 10, 6, 5, 4, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 19, 15, 14, 13, 15, 11, 10, 9, 14, 10, 9, 8, 13, 9, 8, 7, 15, 11, 10, 9, 11, 7, 6, 5, 10, 6, 5, 4, 9, 5, 4, 3, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 18, 14, 13, 12, 14, 10, 9, 8, 13, 9, 8, 7, 12, 8, 7, 6, 14, 10, 9, 8, 10, 6, 5, 4, 9, 5, 4, 3, 8, 4, 3, 2, 13, 9, 8, 7, 9, 5, 4, 3, 8, 4, 3, 2, 7, 3, 2, 1, 12, 8, 7, 6, 8, 4, 3, 2, 7, 3, 2, 1, 6, 2, 1, 0}}; ////////////////////////////////////////////// // topval is the topval of an array of values of len in l_capturing() ////////////////////////////////////////////// unsigned int topval[170] = { 1, 2, 3, 5, 7, 11, 17, 25, 38, 57, 86, 129, 194, 291, 437, 656, 854, 1110, 1443, 1876, 2439, 3171, 3475, 3823, 4205, 4626, 5088, 5597, 6157, 6772, 7450, 8195, 9014, 9916, 10907, 11998, 13198, 14518, 15970, 17567, 19323, 21256, 23382, 25720, 28292, 31121, 34233, 37656, 41422, 45564, 50121, 55133, 60646, 66711, 73382, 80721, 88793, 97672, 107439, 118183, 130002, 143002, 157302, 173032, 190335, 209369, 230306, 253337, 278670, 306538, 337191, 370911, 408002, 448802, 493682, 543050, 597356, 657091, 722800, 795081, 874589, 962048, 1058252, 1164078, 1280486, 1408534, 1549388, 1704327, 1874759, 2062236, 2268459, 2495305, 2744836, 3019320, 3321252, 3653374, 4018711, 4420582, 4862641, 5348905, 5883796, 6472176, 7119394, 7831333, 8614467, 9475909, 10423501, 11465851, 12612437, 13873681, 15261050, 16787154, 18465870, 20312458, 22343706, 24578077, 27035886, 29739474, 32713425, 35984770, 39583245, 43541573, 47895730, 52685306, 57953837, 63749221, 70124148, 77136564, 84850228, 93335252, 102668779, 112935659, 124229227, 136652151, 150317384, 165349128, 181884040, 200072456, 220079703, 242087671, 266296456, 292926096, 322218735, 354440623, 389884688, 428873168, 471760495, 518936559, 570830240, 627913311, 690704607, 759775136, 835752671, 919327967, 1011260767, 1112386880, 1223623232, 1345985727, 1480584256, 1628642751, 1791507135, 1970657856, 2167723648, 2384496256, 2622945920, 2885240448, 3173764736, 3491141248, 3840255616, 4224281216}; unsigned char l_capturing(unsigned int len) { int bottom = 0; int top = 170; unsigned char idx = 85; while (1) { if (idx == 0) { return (idx); } if ((len <= topval[idx]) && (len > topval[idx - 1])) { // printf("len=%u idx=%u\n", len, idx); return (idx); } if (len < topval[idx]) { top = idx - 1; } else { bottom = idx + 1; } idx = (bottom + top) / 2; } } int mod_diff(unsigned int x, unsigned int y, unsigned int R) { int dl = 0; int dr = 0; if (y > x) { dl = (int) (y - x); dr = (int) (x + R - y); } else { dl = (int) (x - y); dr = (int) (y + R - x); } return (dl > dr ? dr : dl); } /////////////////////////////////////////////////////////////// #include #ifdef TLSH_DISTANCE_PARAMETERS #include // for abs() extern int hist_diff1_add; // default value 1 extern int hist_diff2_add; // default value 2 extern int hist_diff3_add; // default value 6 static int pairbit_diff(int pairb, int opairb) { int diff = abs(pairb - opairb); if (diff == 0) { // printf("PBD: %d\n", diff); return (0); } else if (diff == 1) { // printf("PBD: diff=%d %d\n", diff, hist_diff1_add); return (hist_diff1_add); } else if (diff == 2) { // printf("PBD: diff=%d %d\n", diff, hist_diff2_add); return (hist_diff2_add); } // printf("PBD: diff=%d %d\n", diff, hist_diff3_add); return (hist_diff3_add); } static int byte_diff(unsigned char bv, unsigned char obv) { int h1 = (unsigned char) bv / 16; int oh1 = (unsigned char) obv / 16; int h2 = (unsigned char) bv % 16; int oh2 = (unsigned char) obv % 16; int p1 = h1 / 4; int op1 = oh1 / 4; int p2 = h1 % 4; int op2 = oh1 % 4; int p3 = h2 / 4; int op3 = oh2 / 4; int p4 = h2 % 4; int op4 = oh2 % 4; int diff = 0; diff = diff + pairbit_diff(p1, op1); diff = diff + pairbit_diff(p2, op2); diff = diff + pairbit_diff(p3, op3); diff = diff + pairbit_diff(p4, op4); return (diff); } /////////////////////////////////////////////////////////////// static int test_distance = 1; #endif int h_distance(int len, const unsigned char x[], const unsigned char y[]) { int diff = 0; #ifdef TLSH_DISTANCE_PARAMETERS if (test_distance) { for (int i = 0; i < len; i++) { int dist2 = byte_diff(x[i], y[i]); // printf("warning x[%d]=%d y[%d]=%d dist2=%d\n", i, x[i], i, y[i], // dist2); if ((hist_diff1_add == 1) && (hist_diff2_add == 2) && (hist_diff3_add == 6)) { int dist1 = bit_pairs_diff_table[x[i]][y[i]]; if (dist1 != dist2) { printf( "warning x[%d]=%d y[%d]=%d dist1=%d dist2=%d\n", i, x[i], i, y[i], dist1, dist2); } } diff += dist2; } return diff; } #endif for (int i = 0; i < len; i++) { diff += bit_pairs_diff_table[x[i]][y[i]]; } return diff; } unsigned char swap_byte(const unsigned char in) { unsigned char byte = 0; byte = ((in & 0xF0) >> 4) & 0x0F; byte |= ((in & 0x0F) << 4) & 0xF0; return byte; } void to_hex(unsigned char *psrc, int len, char *pdest) { static unsigned char HexLookup[513] = {"000102030405060708090A0B0C0D0E0F" "101112131415161718191A1B1C1D1E1F" "202122232425262728292A2B2C2D2E2F" "303132333435363738393A3B3C3D3E3F" "404142434445464748494A4B4C4D4E4F" "505152535455565758595A5B5C5D5E5F" "606162636465666768696A6B6C6D6E6F" "707172737475767778797A7B7C7D7E7F" "808182838485868788898A8B8C8D8E8F" "909192939495969798999A9B9C9D9E9F" "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF" "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF" "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF" "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF" "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF" "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"}; unsigned short *pwHex = (unsigned short *) HexLookup; unsigned short *pwDest = (unsigned short *) pdest; for (int i = 0; i < len; i++) { *pwDest = pwHex[*psrc]; pwDest++; psrc++; } *((unsigned char *) pwDest) = 0; // terminate the string } void from_hex(const char *psrc, int len, unsigned char *pdest) { static unsigned char DecLookup[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // gap before // first hex // digit 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // 0123456789 0, 0, 0, 0, 0, 0, 0, // :;<=>?@ (gap) 10, 11, 12, 13, 14, 15, // ABCDEF 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // GHIJKLMNOPQRS (gap) 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // TUVWXYZ[/]^_` (gap) 10, 11, 12, 13, 14, 15 // abcdef }; for (int i = 0; i < len; i += 2) { unsigned d = DecLookup[*(unsigned char *) (psrc + i)] << 4; d |= DecLookup[*(unsigned char *) (psrc + i + 1)]; *pdest++ = d; } } yara-4.5.3/libyara/tlshc/tlsh_util.h000066400000000000000000000011651501365277300174130ustar00rootroot00000000000000#ifndef __TLSH_TLSH_UTIL_H__ #define __TLSH_TLSH_UTIL_H__ #ifdef __cplusplus extern "C" { #endif // unsigned char b_mapping(unsigned char salt, unsigned char i, unsigned char // j, unsigned char k); unsigned char l_capturing(unsigned int len); int mod_diff(unsigned int x, unsigned int y, unsigned int R); int h_distance(int len, const unsigned char x[], const unsigned char y[]); void to_hex(unsigned char* psrc, int len, char* pdest); void from_hex(const char* psrc, int len, unsigned char* pdest); unsigned char swap_byte(const unsigned char in); #ifdef __cplusplus } #endif #endif // __TLSH_TLSH_UTIL_H__yara-4.5.3/libyara/yara.pc000066400000000000000000000004361501365277300153760ustar00rootroot00000000000000prefix=/usr/local exec_prefix=${prefix} includedir=${prefix}/include libdir=${exec_prefix}/lib Name: yara Description: YARA library URL: https://virustotal.github.io/yara/ Version: 4.2.2 Requires.private: libcrypto Cflags: -I${includedir} Libs: -L${libdir} -lyara Libs.private: -lm yara-4.5.3/m4/000077500000000000000000000000001501365277300130105ustar00rootroot00000000000000yara-4.5.3/m4/acx_pthread.m4000066400000000000000000000324771501365277300155510ustar00rootroot00000000000000# This was retrieved from # http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?revision=1277&root=avahi # See also (perhaps for new versions?) # http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?root=avahi # # We've rewritten the inconsistency check code (from avahi), to work # more broadly. In particular, it no longer assumes ld accepts -zdefs. # This caused a restructuring of the code, but the functionality has only # changed a little. dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) dnl dnl @summary figure out how to build C programs using POSIX threads dnl dnl This macro figures out how to build C programs using POSIX threads. dnl It sets the PTHREAD_LIBS output variable to the threads library and dnl linker flags, and the PTHREAD_CFLAGS output variable to any special dnl C compiler flags that are needed. (The user can also force certain dnl compiler flags/libs to be tested by setting these environment dnl variables.) dnl dnl Also sets PTHREAD_CC to any special C compiler that is needed for dnl multi-threaded programs (defaults to the value of CC otherwise). dnl (This is necessary on AIX to use the special cc_r compiler alias.) dnl dnl NOTE: You are assumed to not only compile your program with these dnl flags, but also link it with them as well. e.g. you should link dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS dnl $LIBS dnl dnl If you are only building threads programs, you may wish to use dnl these variables in your default LIBS, CFLAGS, and CC: dnl dnl LIBS="$PTHREAD_LIBS $LIBS" dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS" dnl CC="$PTHREAD_CC" dnl dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX). dnl dnl ACTION-IF-FOUND is a list of shell commands to run if a threads dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the dnl default action will define HAVE_PTHREAD. dnl dnl Please let the authors know if this macro fails on any platform, or dnl if you have any other suggestions or comments. This macro was based dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros dnl posted by Alejandro Forero Cuervo to the autoconf macro repository. dnl We are also grateful for the helpful feedback of numerous users. dnl dnl @category InstalledPackages dnl @author Steven G. Johnson dnl @version 2006-05-29 dnl @license GPLWithACException dnl dnl Checks for GCC shared/pthread inconsistency based on work by dnl Marcin Owsiany AC_DEFUN([ACX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_SAVE AC_LANG_C acx_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) AC_MSG_RESULT($acx_pthread_ok) if test x"$acx_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case "${host_cpu}-${host_os}" in *solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags" ;; esac if test x"$acx_pthread_ok" = xno; then for flag in $acx_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) if test x"$acx_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [acx_pthread_ok=yes]) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT($acx_pthread_ok) if test "x$acx_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$acx_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_TRY_LINK([#include ], [int attr=$attr; return attr;], [attr_name=$attr; break]) done AC_MSG_RESULT($attr_name) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case "${host_cpu}-${host_os}" in *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with xlc_r or cc_r if test x"$GCC" != xyes; then AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) else PTHREAD_CC=$CC fi # The next part tries to detect GCC inconsistency with -shared on some # architectures and systems. The problem is that in certain # configurations, when -shared is specified, GCC "forgets" to # internally use various flags which are still necessary. # # Prepare the flags # save_CFLAGS="$CFLAGS" save_LIBS="$LIBS" save_CC="$CC" # Try with the flags determined by the earlier checks. # # -Wl,-z,defs forces link-time symbol resolution, so that the # linking checks with -shared actually have any value # # FIXME: -fPIC is required for -shared on many architectures, # so we specify it here, but the right way would probably be to # properly detect whether it is actually required. CFLAGS="-shared -fPIC -Wl,-z,defs $CFLAGS $PTHREAD_CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CC="$PTHREAD_CC" # In order not to create several levels of indentation, we test # the value of "$done" until we find the cure or run out of ideas. done="no" # First, make sure the CFLAGS we added are actually accepted by our # compiler. If not (and OS X's ld, for instance, does not accept -z), # then we can't do this test. if test x"$done" = xno; then AC_MSG_CHECKING([whether to check for GCC pthread/shared inconsistencies]) AC_TRY_LINK(,, , [done=yes]) if test "x$done" = xyes ; then AC_MSG_RESULT([no]) else AC_MSG_RESULT([yes]) fi fi if test x"$done" = xno; then AC_MSG_CHECKING([whether -pthread is sufficient with -shared]) AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi fi # # Linux gcc on some architectures such as mips/mipsel forgets # about -lpthread # if test x"$done" = xno; then AC_MSG_CHECKING([whether -lpthread fixes that]) LIBS="-lpthread $PTHREAD_LIBS $save_LIBS" AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) PTHREAD_LIBS="-lpthread $PTHREAD_LIBS" else AC_MSG_RESULT([no]) fi fi # # FreeBSD 4.10 gcc forgets to use -lc_r instead of -lc # if test x"$done" = xno; then AC_MSG_CHECKING([whether -lc_r fixes that]) LIBS="-lc_r $PTHREAD_LIBS $save_LIBS" AC_TRY_LINK([#include ], [pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], [done=yes]) if test "x$done" = xyes; then AC_MSG_RESULT([yes]) PTHREAD_LIBS="-lc_r $PTHREAD_LIBS" else AC_MSG_RESULT([no]) fi fi if test x"$done" = xno; then # OK, we have run out of ideas AC_MSG_WARN([Impossible to determine how to use pthreads with shared libraries]) # so it's not safe to assume that we may use pthreads acx_pthread_ok=no fi CFLAGS="$save_CFLAGS" LIBS="$save_LIBS" CC="$save_CC" else PTHREAD_CC="$CC" fi AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_CC) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$acx_pthread_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) : else acx_pthread_ok=no $2 fi AC_LANG_RESTORE ])dnl ACX_PTHREAD yara-4.5.3/sample.file000066400000000000000000000000061501365277300146060ustar00rootroot00000000000000abbbb yara-4.5.3/sample.rules000066400000000000000000000002631501365277300150260ustar00rootroot00000000000000import "pe" rule UPX : Packer { strings: $a = {60 E8 00 00 00 00 58 83 E8 3D 50 8D B8} condition: $a at pe.entry_point } rule test {condition: false} yara-4.5.3/sandbox/000077500000000000000000000000001501365277300141265ustar00rootroot00000000000000yara-4.5.3/sandbox/BUILD.bazel000066400000000000000000000105751501365277300160140ustar00rootroot00000000000000# Copyright (c) 2019. The YARA Authors. All Rights Reserved. # # Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation and/or # other materials provided with the distribution. # # 3. Neither the name of the copyright holder nor the names of its contributors # may be used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. load("@rules_cc//cc:defs.bzl", "cc_proto_library") load("@rules_proto//proto:defs.bzl", "proto_library") load( "@com_google_sandboxed_api//sandboxed_api/bazel:proto.bzl", "sapi_proto_library", ) load( "@com_google_sandboxed_api//sandboxed_api/bazel:sapi.bzl", "sapi_library", ) # Proto message that stores YARA matches. Used to communicate matches from # the sandboxee to the host code. sapi_proto_library( name = "yara_matches", srcs = ["yara_matches.proto"], ) # Library with a callback function to collect YARA matches into a YaraMatches # proto cc_library( name = "collect_matches", srcs = ["collect_matches.cc"], hdrs = ["collect_matches.h"], visibility = ["//visibility:public"], deps = [ ":yara_matches_cc_proto", "//:yara", ], ) # The sandboxee side of the YARA sandbox. This implements a dispatch queue # shared by multiple worker threads. YARA rules are shared across all threads # to keep memory usage down. cc_library( name = "yara_entry_points", srcs = ["yara_entry_points.cc"], deps = [ ":collect_matches", ":yara_matches_cc_proto", "//:libyara", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:node_hash_map", "@com_google_absl//absl/strings", "@com_google_absl//absl/synchronization", ], alwayslink = 1, ) # Sandboxed API for YARA. This is what clients of this library should use. The # API is intentionally minimal and may be extended in the future. # See the "sandboxed-yara" target for an example on how to use this from code. sapi_library( name = "yara_sapi", srcs = ["yara_transaction.cc"], hdrs = ["yara_transaction.h"], embed = True, functions = [ "YaraAsyncScanFd", "YaraGetScanResult", "YaraInitWorkers", "YaraLoadRules", ], input_files = ["yara_entry_points.cc"], lib = ":yara_entry_points", lib_name = "Yara", namespace = "yara::sandbox", visibility = ["//visibility:public"], deps = [ ":yara_matches_cc_proto", "//:yara_errors", "@com_google_absl//absl/memory", "@com_google_absl//absl/synchronization", "@com_google_absl//absl/time", "@com_google_sandboxed_api//sandboxed_api/sandbox2/util:bpf_helper", "@com_google_sandboxed_api//sandboxed_api/util:status", ], ) cc_test( name = "yara_transaction_test", srcs = ["yara_transaction_test.cc"], deps = [ ":yara_sapi", "@com_google_googletest//:gtest_main", "@com_google_sandboxed_api//sandboxed_api/util:status_matchers", ], ) # Sandboxed command-line executable demonstrating how to use the YARA SAPI. cc_binary( name = "sandboxed_yara", srcs = ["sandboxed_yara.cc"], deps = [ ":yara_sapi", "@com_google_absl//absl/flags:parse", "@com_google_absl//absl/strings", ], ) yara-4.5.3/sandbox/collect_matches.cc000066400000000000000000000051041501365277300175660ustar00rootroot00000000000000/* Copyright (c) 2019. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "sandbox/collect_matches.h" #include "libyara/include/yara.h" #include "sandbox/yara_matches.pb.h" namespace yara { int CollectMatches( YR_SCAN_CONTEXT*, int message, void* message_data, void* user_data) { if (message != CALLBACK_MSG_RULE_MATCHING) { return ERROR_SUCCESS; // There are no matching rules, simply return } auto* rule = static_cast(message_data); YR_META* rule_meta = rule->metas; auto* match = reinterpret_cast(user_data)->add_match(); if (rule->ns != nullptr && rule->ns->name != nullptr) { match->mutable_id()->set_rule_namespace(rule->ns->name); } match->mutable_id()->set_rule_name(rule->identifier); yr_rule_metas_foreach(rule, rule_meta) { auto* meta = match->add_meta(); meta->set_identifier(rule_meta->identifier); switch (rule_meta->type) { case META_TYPE_BOOLEAN: case META_TYPE_INTEGER: meta->set_int_value(rule_meta->integer); break; case META_TYPE_STRING: meta->set_bytes_value(rule_meta->string); break; } } return ERROR_SUCCESS; } } // namespace yara yara-4.5.3/sandbox/collect_matches.h000066400000000000000000000035411501365277300174330ustar00rootroot00000000000000/* Copyright (c) 2019. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef SANDBOX_COLLECT_MATCHES_H_ #define SANDBOX_COLLECT_MATCHES_H_ struct YR_SCAN_CONTEXT; namespace yara { // Callback function for yr_scan_mem() that collects YARA matches in a // YaraMatches proto given in user_data. int CollectMatches(YR_SCAN_CONTEXT*, int message, void* message_data, void* user_data); } // namespace yara #endif // SANDBOX_COLLECT_MATCHES_H_ yara-4.5.3/sandbox/sandboxed_yara.cc000066400000000000000000000113651501365277300174260ustar00rootroot00000000000000/* Copyright (c) 2019. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "sandbox/yara_transaction.h" #include "sandboxed_api/util/statusor.h" // TODO(cblichmann): SAPI leaks these symbols currently. #undef ABSL_FLAG #undef ABSL_DECLARE_FLAG #undef ABSL_RETIRED_FLAG #include "absl/flags/flag.h" #include "absl/flags/parse.h" #include "absl/flags/usage.h" #include "absl/status/status.h" #include "absl/strings/str_cat.h" #include "absl/time/time.h" ABSL_FLAG(std::string, identifier, "", "print only rules with this name"); ABSL_FLAG(int, timeout, 5, "abort scanning after the given number of seconds"); namespace yara { namespace { ::sapi::StatusOr ReadFileToString(absl::string_view filename) { std::ifstream input(std::string(filename), std::ios::in | std::ios::binary); std::ostringstream output; output << input.rdbuf(); if (!input) { return absl::UnknownError( absl::StrCat("Cannot read file '", filename, "'")); } return output.str(); } } // namespace // Implements a subset of the YARA command line scanner, but runs the actual // scan inside of a sandbox. absl::Status YaraMain(const std::vector& args) { if (args.size() < 3) { return absl::InvalidArgumentError("Missing operand. Try '--help'."); } // Get file to scan and concatenate all the YARA rules from the specified // files. std::string scan_filename = args.back(); std::string all_rules; for (size_t i = 1; i != args.size() - 1; ++i) { SAPI_ASSIGN_OR_RETURN(std::string rules, ReadFileToString(args[i])); absl::StrAppend(&all_rules, rules, "\n"); } SAPI_ASSIGN_OR_RETURN( auto transaction, YaraTransaction::Create( YaraTransaction::Options() .set_scan_timeout(absl::Seconds(absl::GetFlag(FLAGS_timeout))) .set_num_workers(1))); SAPI_ASSIGN_OR_RETURN( int num_rules ABSL_ATTRIBUTE_UNUSED, transaction->LoadRules(all_rules)); struct FDCloser { ~FDCloser() { close(fd); } int fd; } fd_closer{open(scan_filename.c_str(), O_RDONLY)}; if (fd_closer.fd == -1) { return absl::UnknownError(absl::StrCat( "Cannot open file '", scan_filename, "': ", strerror(errno))); } SAPI_ASSIGN_OR_RETURN(YaraMatches matches, transaction->ScanFd(fd_closer.fd)); for (const auto& match : matches.match()) { const std::string& rule_name = match.id().rule_name(); if (absl::GetFlag(FLAGS_identifier).empty() || (absl::GetFlag(FLAGS_identifier) == rule_name)) { absl::PrintF("%s %s\n", rule_name, scan_filename); } } return absl::OkStatus(); } } // namespace yara int main(int argc, char* argv[]) { absl::string_view argv0 = argv[0]; { auto last_slash_pos = argv0.find_last_of("/\\"); if (last_slash_pos != absl::string_view::npos) { argv0 = argv0.substr(last_slash_pos + 1); } } absl::SetProgramUsageMessage(absl::StrCat( "YARA, the pattern matching swiss army knife.\n", "Usage: ", argv0, " [OPTION] RULES_FILE... FILE")); absl::Status status = ::yara::YaraMain(absl::ParseCommandLine(argc, argv)); if (!status.ok()) { absl::FPrintF(stderr, "ERROR: %s\n", status.message()); return EXIT_FAILURE; } return EXIT_SUCCESS; } yara-4.5.3/sandbox/yara_entry_points.cc000066400000000000000000000167241501365277300202200ustar00rootroot00000000000000/* Copyright (c) 2019. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "absl/base/attributes.h" #include "absl/container/node_hash_map.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "libyara/include/yara.h" #include "sandbox/collect_matches.h" #include "sandbox/yara_matches.pb.h" namespace yara { namespace { struct ScanTask { // Key into the g_results map, used by YaraGetScanResult() uint64_t result_id; // File descriptor containing the data to scan int data_fd; // File descriptor used to signal the host code on scan completion int event_fd; // Scan timeout. YARA only supports second granularity. absl::Duration timeout; }; struct ScanResult { int code; YaraMatches matches; }; static const bool g_init_done ABSL_ATTRIBUTE_UNUSED = []() { // Disable output buffering setbuf(stdout, nullptr); setbuf(stderr, nullptr); // Increase stack size struct rlimit stack_limit; stack_limit.rlim_cur = 1 << 20 /* 1 MiB */; stack_limit.rlim_max = stack_limit.rlim_cur; ABSL_RAW_CHECK(setrlimit(RLIMIT_STACK, &stack_limit) == 0, strerror(errno)); // Initialize YARA. Note that the sandboxed code never calls yr_finalize(). // Instead, the OS will clean up on process exit. const int err = yr_initialize(); ABSL_RAW_CHECK( err == ERROR_SUCCESS, absl::StrCat("yr_initialize() failed with code: ", err).c_str()); return true; }(); // Global dispatch queue used to schedule new scan tasks ABSL_CONST_INIT static absl::Mutex g_queue_mutex(absl::kConstInit); static auto* g_queue GUARDED_BY(g_queue_mutex) = new std::queue(); static uint64_t g_result_id GUARDED_BY(g_queue_mutex) = 0; // This map tracks scan results. It relies on pointers staying stable, so this // uses a node_hash_map<> instead of a flat_hash_map<>. ABSL_CONST_INIT static absl::Mutex g_results_mutex(absl::kConstInit); static auto* g_results GUARDED_BY(g_results_mutex) = new absl::node_hash_map(); ABSL_CONST_INIT static absl::Mutex g_rules_mutex(absl::kConstInit); static YR_RULES* g_rules GUARDED_BY(g_rules_mutex) = nullptr; void ScanWorker() { while (true) { // Wait for and retrieve a new ScanTask from the queue. g_queue_mutex.LockWhen(absl::Condition( +[](std::queue* queue) { return !queue->empty(); }, g_queue)); const ScanTask task = std::move(g_queue->front()); g_queue->pop(); g_queue_mutex.Unlock(); ScanResult result; { absl::ReaderMutexLock lock(&g_rules_mutex); result.code = yr_rules_scan_fd( g_rules, task.data_fd, // Disable SIGSEGV handler, allowing YARA to crash/coredump. SCAN_FLAGS_NO_TRYCATCH, CollectMatches, /*user_data=*/reinterpret_cast(&result.matches), absl::ToInt64Seconds(task.timeout)); } { absl::MutexLock lock(&g_results_mutex); (*g_results)[task.result_id] = std::move(result); } // Unblock any waiting clients on the host side. This should always succeed // writing 8 bytes, as long as the event_fd stays open in this function, // hence the CHECK. uint64_t unblock_value = 1; ABSL_RAW_CHECK( write(task.event_fd, &unblock_value, sizeof(unblock_value)) == sizeof(unblock_value), strerror(errno)); close(task.event_fd); close(task.data_fd); } } } // namespace extern "C" void YaraInitWorkers(int num_workers) { const int num_threads = std::min( static_cast(std::min(num_workers, YR_MAX_THREADS)), std::thread::hardware_concurrency()); static auto* workers = new std::vector(); workers->reserve(num_threads); for (int i = 0; i < num_threads; ++i) { workers->emplace_back(ScanWorker); } } // Initializes the global YARA rules set from a string. Returns the number of // rules loaded. Extended error information can be found in status if it is not // nullptr. extern "C" int YaraLoadRules(const char* rule_string, YaraStatus* error_status) { _YR_COMPILER* compiler; int error = yr_compiler_create(&compiler); if (error != ERROR_SUCCESS) { if (error_status) { error_status->set_code(error); } return 0; } std::unique_ptr<_YR_COMPILER, void (*)(_YR_COMPILER*)> compiler_cleanup( compiler, yr_compiler_destroy); if (yr_compiler_add_string(compiler, rule_string, nullptr) != 0) { if (error_status) { error_status->set_code(compiler->last_error); char message[512] = {'\0'}; yr_compiler_get_error_message(compiler, message, sizeof(message)); error_status->set_message(message); } return 0; } YR_RULES* rules = nullptr; error = yr_compiler_get_rules(compiler, &rules); if (error != ERROR_SUCCESS) { if (error_status) { error_status->set_code(error); } return 0; } int num_rules = 0; YR_RULE* rule; yr_rules_foreach(rules, rule) { ++num_rules; } absl::MutexLock lock(&g_rules_mutex); if (g_rules) { yr_rules_destroy(g_rules); } g_rules = rules; return num_rules; } // Schedules a new asynchronous YARA scan task on the data in the specified file // descriptor. Notifies host code via writing to the event_fd file descriptor. // Returns a unique identifier that can be used to retrieve the results. extern "C" uint64_t YaraAsyncScanFd(int data_fd, int event_fd, int timeout_secs) { absl::MutexLock queue_lock(&g_queue_mutex); ++g_result_id; g_queue->push({g_result_id, data_fd, event_fd, absl::Seconds(timeout_secs)}); return g_result_id; } extern "C" int YaraGetScanResult(uint64_t result_id, YaraMatches* matches) { absl::MutexLock lock(&g_results_mutex); auto result = g_results->find(result_id); if (result == g_results->end()) { return -1; } int code = result->second.code; *matches = std::move(result->second.matches); g_results->erase(result); return code; } } // namespace yara yara-4.5.3/sandbox/yara_matches.proto000066400000000000000000000041641501365277300176600ustar00rootroot00000000000000/* Copyright (c) 2019. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ syntax = "proto3"; package yara; // Identifies a single rule inside a namespace message YaraRuleId { string rule_namespace = 1; // Currently unused by yara_entrypoints.cc string rule_name = 2; } // Holds N mappings for the matches. message YaraMatches { // Holds one mapping from (namespace, name) --> N key-value entries. message Match { message Meta { string identifier = 1; oneof value { bytes bytes_value = 2; int64 int_value = 3; } } YaraRuleId id = 1; repeated Meta meta = 2; } repeated Match match = 1; } message YaraStatus { int64 code = 1; int64 line_number = 2; string message = 3; } yara-4.5.3/sandbox/yara_transaction.cc000066400000000000000000000132541501365277300200030ustar00rootroot00000000000000/* Copyright (c) 2019. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "sandbox/yara_transaction.h" #include #include #include #include "absl/strings/str_cat.h" #include "libyara/include/yara/error.h" #include "sandboxed_api/util/status_macros.h" namespace yara { absl::Mutex YaraTransaction::mutex_(absl::kConstInit); ::sapi::StatusOr> YaraTransaction::Create( Options options) { auto transaction = absl::WrapUnique( new YaraTransaction(options.scan_timeout)); // "Run" the transaction in order to initialize the underlying sandbox. SAPI_RETURN_IF_ERROR(transaction->Run()); sandbox::YaraApi api(transaction->sandbox()); SAPI_RETURN_IF_ERROR( api.YaraInitWorkers(options.num_workers >= 1 ? options.num_workers : 1)); return transaction; } ::sapi::StatusOr YaraTransaction::LoadRules(const std::string& rule_string) { absl::MutexLock lock(&mutex_); sandbox::YaraApi api(sandbox()); ::sapi::v::ConstCStr rule_string_sapi(rule_string.c_str()); YaraStatus error_status; ::sapi::v::Proto error_status_sapi(error_status); SAPI_ASSIGN_OR_RETURN( int num_rules, api.YaraLoadRules( rule_string_sapi.PtrBefore(), error_status_sapi.PtrBoth())); if (num_rules <= 0) { auto error_status_copy = error_status_sapi.GetProtoCopy(); if (!error_status_copy) { return absl::UnknownError("Deserialization of response failed"); } return absl::InvalidArgumentError(error_status_copy->message()); } return num_rules; } ::sapi::StatusOr YaraTransaction::ScanFd(int fd) { int local_event_fd = eventfd(0 /* initval */, 0 /* flags */); if (local_event_fd == -1) { return absl::InternalError( absl::StrCat("eventfd() error: ", strerror(errno))); } struct FDCloser { ~FDCloser() { close(event_fd); } int event_fd; } event_fd_closer = {local_event_fd}; sandbox::YaraApi api(sandbox()); uint64_t result_id; { absl::MutexLock lock(&mutex_); // Note: These SAPI Fd objects use the underlying sandbox comms to // synchronize. Hence they must live within this locked scope. ::sapi::v::Fd event_fd(local_event_fd); SAPI_RETURN_IF_ERROR(sandbox()->TransferToSandboxee(&event_fd)); event_fd.OwnLocalFd(false); // Needs to be valid during poll() event_fd.OwnRemoteFd(false); // Sandboxee will close ::sapi::v::Fd data_fd(fd); SAPI_RETURN_IF_ERROR(sandbox()->TransferToSandboxee(&data_fd)); data_fd.OwnLocalFd(false); // To be closed by caller data_fd.OwnRemoteFd(false); // Sandboxee will close SAPI_ASSIGN_OR_RETURN( result_id, api.YaraAsyncScanFd( data_fd.GetRemoteFd(), event_fd.GetRemoteFd(), absl::ToInt64Seconds(scan_timeout_))); } pollfd poll_events{local_event_fd, POLLIN}; int poll_result; // TEMP_FAILURE_RETRY is a GNU extension that retries if the call returns // EINTR. poll_result = TEMP_FAILURE_RETRY(poll( &poll_events, 1 /* nfds */, // Add extra time to allow code inside the sandbox to time out first. absl::ToInt64Milliseconds(scan_timeout_ + absl::Seconds(10)))); if (poll_result == 0) { return absl::DeadlineExceededError("Scan timeout during poll()"); } if (poll_result == -1) { return absl::InternalError(absl::StrCat("poll() error: ", strerror(errno))); } if (poll_events.revents & POLLHUP || poll_events.revents & POLLERR || poll_events.revents & POLLNVAL) { return absl::InternalError( absl::StrCat("poll() error, revents: ", poll_events.revents)); } absl::MutexLock lock(&mutex_); YaraMatches matches; ::sapi::v::Proto matches_sapi(matches); SAPI_ASSIGN_OR_RETURN( int scan_result, api.YaraGetScanResult(result_id, matches_sapi.PtrBoth())); switch (scan_result) { case ERROR_SUCCESS: case ERROR_TOO_MANY_MATCHES: { auto matches_copy = matches_sapi.GetProtoCopy(); if (!matches_copy) { return absl::UnknownError("Deserialization of response failed"); } return *matches_copy; } case ERROR_SCAN_TIMEOUT: return absl::DeadlineExceededError("Scan timeout"); } return absl::InternalError(absl::StrCat("Error during scan: ", scan_result)); } } // namespace yara yara-4.5.3/sandbox/yara_transaction.h000066400000000000000000000107051501365277300176430ustar00rootroot00000000000000/* Copyright (c) 2019. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef SANDBOX_TRANSACTION_H_ #define SANDBOX_TRANSACTION_H_ #include #include #include #include "absl/memory/memory.h" #include "absl/status/status.h" #include "absl/synchronization/mutex.h" #include "absl/time/time.h" #include "sandbox/yara_matches.pb.h" #include "sandbox/yara_sapi.sapi.h" #include "sandboxed_api/sandbox.h" #include "sandboxed_api/sandbox2/executor.h" #include "sandboxed_api/sandbox2/policy.h" #include "sandboxed_api/sandbox2/util.h" #include "sandboxed_api/sandbox2/util/bpf_helper.h" #include "sandboxed_api/transaction.h" namespace yara { class YaraSandbox : public sandbox::YaraSandbox { public: std::unique_ptr ModifyPolicy( sandbox2::PolicyBuilder* builder) override { return (*builder) .AllowStaticStartup() .AllowMmap() .AllowFork() // Thread creation .AllowSyscalls({ __NR_madvise, __NR_mprotect, __NR_munlock, __NR_poll, __NR_sched_getparam, __NR_sched_getscheduler, __NR_sched_yield, }) .BuildOrDie(); } void ModifyExecutor(sandbox2::Executor* executor) override { (*executor->limits()) // Remove limit on file descriptor bytes. .set_rlimit_fsize(RLIM64_INFINITY) // Wall-time limit per call will be enforced by the Transaction. .set_rlimit_cpu(RLIM64_INFINITY); } }; // Transaction class to run sandboxed Yara scans of the contents of file // descriptors. This class is thread-safe and access to the sandboxee is // multiplexed so that multiple threads can share the transaction. class YaraTransaction : public ::sapi::Transaction { public: struct Options { absl::Duration scan_timeout; int num_workers; Options& set_scan_timeout(absl::Duration value) { scan_timeout = value; return *this; } Options& set_num_workers(int value) { num_workers = value; return *this; } }; // Creates and initializes an instance of this transaction class with the // specified scan_timeout. static ::sapi::StatusOr> Create( Options options = {}); // Loads new Yara rules into the sandboxee. Returns the number of rules // loaded. Only one set of rules can be active at any given time. This method // blocks until all concurrent YARA scans are completed before updating the // rules. ::sapi::StatusOr LoadRules(const std::string& rule_string) LOCKS_EXCLUDED(mutex_); // Scans the contents of the specified file descriptor. // Returns DeadlineExceededError if the scan timed out. ::sapi::StatusOr ScanFd(int fd) LOCKS_EXCLUDED(mutex_); private: explicit YaraTransaction(absl::Duration scan_timeout) : ::sapi::Transaction(absl::make_unique()) {} // Mutex to guard communication with the sandboxee static absl::Mutex mutex_; absl::Duration scan_timeout_; }; } // namespace yara #endif // SANDBOX_TRANSACTION_H_ yara-4.5.3/sandbox/yara_transaction_test.cc000066400000000000000000000130521501365277300210360ustar00rootroot00000000000000/* Copyright (c) 2019. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "sandbox/yara_transaction.h" #include // __NR_memdfd_create #include #include #include #include #include #include "absl/strings/str_cat.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include "sandbox/yara_matches.pb.h" #include "sandboxed_api/util/status_matchers.h" #include "sandboxed_api/util/statusor.h" using ::sapi::IsOk; using ::testing::Eq; using ::testing::StrEq; namespace yara { namespace { // Wraps an in-memory file descriptor created by memfd_create(). class MemoryFD { public: static ::sapi::StatusOr CreateWithContent(absl::string_view content) { MemoryFD mem_fd; // Avoid dependency on UAPI headers constexpr uintptr_t MFD_CLOEXEC = 0x0001U; constexpr const char* kName = "memfd"; mem_fd.fd_ = syscall( __NR_memfd_create, reinterpret_cast(kName), MFD_CLOEXEC); if (mem_fd.fd_ == -1) { return absl::UnknownError(absl::StrCat("memfd(): ", strerror(errno))); } if (ftruncate(mem_fd.fd_, content.size()) == -1) { return absl::UnknownError(absl::StrCat("ftruncate(): ", strerror(errno))); } while (!content.empty()) { ssize_t written = TEMP_FAILURE_RETRY( write(mem_fd.fd_, content.data(), content.size())); if (written <= 0) { return absl::UnknownError(absl::StrCat("write(): ", strerror(errno))); } content.remove_prefix(written); } return mem_fd; } MemoryFD(MemoryFD&& other) { *this = std::move(other); } MemoryFD& operator=(MemoryFD&& other) { fd_ = other.fd_; other.fd_ = 0; return *this; } ~MemoryFD() { if (fd_ > 0) { close(fd_); }; } int fd() const { return fd_; } private: MemoryFD() = default; int fd_; }; class TransactionTest : public ::testing::Test { protected: void SetUp() override { SAPI_ASSERT_OK_AND_ASSIGN( transaction_, YaraTransaction::Create(YaraTransaction::Options{} .set_scan_timeout(absl::Minutes(1)) .set_num_workers(16))); } ::sapi::StatusOr ScanString(absl::string_view content) { SAPI_ASSIGN_OR_RETURN( MemoryFD mem_fd, MemoryFD::CreateWithContent(content)); return transaction_->ScanFd(mem_fd.fd()); } std::unique_ptr transaction_; }; TEST_F(TransactionTest, BasicFunctionality) { ASSERT_THAT( transaction_ ->LoadRules(R"( rule Number { strings: $ = "123" condition: all of them } rule Color { strings: $ = "green" condition: all of them } rule Keyboard { strings: $ = "dvorak" condition: all of them })") .ValueOrDie(), Eq(3)); SAPI_ASSERT_OK_AND_ASSIGN(YaraMatches matches, ScanString("qwerty 123")); EXPECT_THAT(matches.match_size(), Eq(1)); EXPECT_THAT(matches.match(0).id().rule_name(), StrEq("Number")); SAPI_ASSERT_OK_AND_ASSIGN(matches, ScanString("green dvorak 456")); EXPECT_THAT(matches.match_size(), Eq(2)); EXPECT_THAT(matches.match(0).id().rule_name(), StrEq("Color")); EXPECT_THAT(matches.match(1).id().rule_name(), StrEq("Keyboard")); } TEST_F(TransactionTest, ConcurrentScanStressTest) { ASSERT_THAT( transaction_ ->LoadRules(R"( rule Simple { strings: $ = "A" condition: all of them })") .ValueOrDie(), Eq(1)); // Large number of threads during testing to increase likelihood of exposing // race conditions in threading code. constexpr int kThreads = 64; std::vector bundle; for (int i = 0; i < kThreads; ++i) { bundle.emplace_back([this, i]() { std::string buf((i + 1) * 102400, 'B'); buf.append("A"); // Force the match to be at the very end SAPI_ASSERT_OK_AND_ASSIGN(YaraMatches matches, ScanString(buf)); ASSERT_THAT(matches.match_size(), Eq(1)); EXPECT_THAT(matches.match(0).id().rule_name(), StrEq("Simple")); }); } for (auto& thread : bundle) { thread.join(); } } } // namespace } // namespace yara yara-4.5.3/test.rules000066400000000000000000000000331501365277300145170ustar00rootroot00000000000000rule t { condition: true } yara-4.5.3/test.yar000066400000000000000000000037761501365277300142010ustar00rootroot00000000000000import "pe" rule M_Dropper_DRIPDRIVE_2 { meta: author = "Mandiant" md5 = "c8ebaf77bb9905ef84b28510de6c9d0e" date_created = "2024-01-08" date_modified = "2024-01-08" rev = "1" strings: $s1 = "########:download ok!" ascii wide $s2 = "########:run command line:" ascii wide $s3 = "########:start install cef!" ascii wide $s4 = "/install" wide $s5 = "/update" wide $s6 = "MachineGuid" wide $s7 = "SOFTWARE\\Microsoft\\Cryptography" wide $asm1 = { 84 C0 75 ?? 2B F1 0F 57 C0 66 0F 13 44 24 ?? 39 5C 24 ?? 7C ?? 8B 7C 24 ?? 7F ?? 3B FB 76 ?? 8B 44 24 ?? 8B 4C 24 ?? 89 44 24 ?? 89 4C 24 ?? 53 56 50 51 E8 ?? ?? ?? ?? 8B 4C 24 ?? 8B 54 24 ?? 8A 44 04 ?? 30 04 11 83 C1 01 8B 44 24 ?? 13 C3 89 4C 24 ?? 89 44 24 ?? 3B 44 24 ?? 7C ?? 7F ?? 3B CF 72 ?? } condition: (uint16(0) == 0x5A4D) and (uint32(uint32(0x3C)) == 0x00004550) and (for any i in (0 .. pe.number_of_resources - 1) : ( pe.resources[i].type_string == "F\x00I\x00L\x00E\x00" )) and (4 of ($s*)) and (all of ($asm*)) } import "pe" rule M_APT_Dropper_DRIPDRIVE_1 { meta: author = "Mandiant" date_created = "2024-02-06" date_modified = "2024-02-06" md5 = "cc3b8573e7955c3fa90d98343f389732" rev = 1 strings: $str1 = "########:start install cef!" $str2 = "########:delete xp file:%s!" $str3 = "########:install cef ok!" $str4 = "########:start update cef!" $str5 = "########:no use update and run wintool!" $str6 = "########:download update!" $str7 = "########:download failed!" $str8 = "########:download ok!" $str9 = "decrypt ok!" $str10 = "########:install update close!" $str11 = "########:run command line" wide fullword $p1 = "Global\\GUID(A3AC453A-543D-4FC6-9465-F8897B8F67E5)" wide fullword $p2 = "/install" wide fullword $p3 = "/update" wide fullword $p4 = "TASKKILL /F /IM %s" wide fullword condition: uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550 and 8 of ($str*) and all of ($p*) and for any i in (0 .. pe.number_of_resources - 1) : ( pe.resources[i].type_string == "F\x00I\x00L\x00E\x00" ) } yara-4.5.3/tests/000077500000000000000000000000001501365277300136325ustar00rootroot00000000000000yara-4.5.3/tests/blob.h000066400000000000000000005200741501365277300147310ustar00rootroot00000000000000/* Copyright (c) 2016. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ uint8_t PE32_FILE[] = { 0x4d, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x50, 0x45, 0x00, 0x00, 0x4c, 0x01, 0x01, 0x00, 0x5d, 0xbe, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x03, 0x01, 0x0b, 0x01, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x60, 0x6a, 0x2a, 0x58, 0xc3, }; uint8_t ELF32_FILE[] = { 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x60, 0x80, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x01, 0x00, 0x28, 0x00, 0x04, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x08, 0x00, 0x80, 0x04, 0x08, 0x6c, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xbb, 0x2a, 0x00, 0x00, 0x00, 0xcd, 0x80, 0x00, 0x54, 0x68, 0x65, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x69, 0x64, 0x65, 0x20, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x72, 0x20, 0x32, 0x2e, 0x30, 0x35, 0x2e, 0x30, 0x31, 0x00, 0x00, 0x2e, 0x73, 0x68, 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x00, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x60, 0x80, 0x04, 0x08, 0x60, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; uint8_t ELF64_FILE[] = { 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x01, 0x00, 0x40, 0x00, 0x04, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xbb, 0x2a, 0x00, 0x00, 0x00, 0xcd, 0x80, 0x00, 0x54, 0x68, 0x65, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x69, 0x64, 0x65, 0x20, 0x41, 0x73, 0x73, 0x65, 0x6d, 0x62, 0x6c, 0x65, 0x72, 0x20, 0x32, 0x2e, 0x30, 0x35, 0x2e, 0x30, 0x31, 0x00, 0x00, 0x2e, 0x73, 0x68, 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x00, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 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, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 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, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 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, }; uint8_t ELF32_NOSECTIONS[] = { 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x04, 0x08, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x02, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x08, 0x00, 0x80, 0x04, 0x08, 0xac, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x74, 0x80, 0x04, 0x08, 0x74, 0x80, 0x04, 0x08, 0x24, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00, 0x72, 0x5c, 0x33, 0xa6, 0xcd, 0xed, 0x46, 0xf2, 0xc7, 0xa2, 0x8c, 0x1f, 0xbd, 0x65, 0x7a, 0xd1, 0x9f, 0x0f, 0x51, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xbb, 0x2a, 0x00, 0x00, 0x00, 0xcd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t ELF32_SHAREDOBJ[] = { 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x54, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x05, 0x00, 0x28, 0x00, 0x09, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x01, 0x00, 0x00, 0xac, 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa8, 0x0f, 0x00, 0x00, 0xa8, 0x1f, 0x00, 0x00, 0xa8, 0x1f, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xa8, 0x0f, 0x00, 0x00, 0xa8, 0x1f, 0x00, 0x00, 0xa8, 0x1f, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x52, 0xe5, 0x74, 0x64, 0xa8, 0x0f, 0x00, 0x00, 0xa8, 0x1f, 0x00, 0x00, 0xa8, 0x1f, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00, 0x6e, 0x96, 0x9b, 0xbc, 0x8b, 0x0c, 0x9d, 0x95, 0x29, 0xfc, 0x07, 0x04, 0x15, 0x95, 0xc5, 0xf0, 0xb9, 0xd5, 0xcd, 0xae, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x44, 0x06, 0x29, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x45, 0xd5, 0xec, 0xbb, 0xe3, 0x92, 0x7c, 0x32, 0x62, 0xdb, 0xed, 0xd9, 0x71, 0x58, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x07, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x07, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x07, 0x00, 0x00, 0x5f, 0x65, 0x64, 0x61, 0x74, 0x61, 0x00, 0x5f, 0x5f, 0x62, 0x73, 0x73, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x5f, 0x65, 0x6e, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xbb, 0x2a, 0x00, 0x00, 0x00, 0xcd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0xfe, 0xff, 0x6f, 0xf8, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x0b, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x73, 0x68, 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x6e, 0x6f, 0x74, 0x65, 0x2e, 0x67, 0x6e, 0x75, 0x2e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2d, 0x69, 0x64, 0x00, 0x2e, 0x67, 0x6e, 0x75, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x73, 0x79, 0x6d, 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x73, 0x74, 0x72, 0x00, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x00, 0x2e, 0x65, 0x68, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xf6, 0xff, 0xff, 0x6f, 0x02, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xac, 0x01, 0x00, 0x00, 0xac, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xa8, 0x1f, 0x00, 0x00, 0xa8, 0x0f, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; unsigned char ELF32_MIPS_FILE[] = { 0x7f, 0x45, 0x4c, 0x46, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, 0x06, 0x10, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x1f, 0x28, 0x00, 0x00, 0x10, 0x07, 0x00, 0x34, 0x00, 0x20, 0x00, 0x0a, 0x00, 0x28, 0x00, 0x23, 0x00, 0x20, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x34, 0x00, 0x40, 0x00, 0x34, 0x00, 0x40, 0x00, 0x34, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x74, 0x00, 0x40, 0x01, 0x74, 0x00, 0x40, 0x01, 0x74, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x70, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x90, 0x00, 0x40, 0x01, 0x90, 0x00, 0x40, 0x01, 0x90, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa8, 0x00, 0x40, 0x01, 0xa8, 0x00, 0x40, 0x01, 0xa8, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x09, 0x5c, 0x00, 0x00, 0x09, 0x5c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f, 0xec, 0x00, 0x41, 0x0f, 0xec, 0x00, 0x41, 0x0f, 0xec, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x40, 0x01, 0xc0, 0x00, 0x40, 0x01, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x64, 0x74, 0xe5, 0x51, 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, 0x10, 0x64, 0x74, 0xe5, 0x52, 0x00, 0x00, 0x0f, 0xec, 0x00, 0x41, 0x0f, 0xec, 0x00, 0x41, 0x0f, 0xec, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 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, 0x04, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x6c, 0x64, 0x2d, 0x6d, 0x75, 0x73, 0x6c, 0x2d, 0x6d, 0x69, 0x70, 0x73, 0x2e, 0x73, 0x6f, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x00, 0x00, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x90, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x40, 0x05, 0x8c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x40, 0x09, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x40, 0x02, 0x80, 0x00, 0x00, 0x00, 0x05, 0x00, 0x40, 0x04, 0x84, 0x00, 0x00, 0x00, 0x06, 0x00, 0x40, 0x03, 0x24, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x70, 0x00, 0x00, 0x16, 0x00, 0x41, 0x10, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x41, 0x10, 0x10, 0x70, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x70, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x70, 0x00, 0x00, 0x06, 0x00, 0x40, 0x00, 0x00, 0x70, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x08, 0x70, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x16, 0x70, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x20, 0x70, 0x00, 0x00, 0x13, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x14, 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, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 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, 0xc1, 0x00, 0x41, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0xff, 0xf1, 0x00, 0x00, 0x00, 0x07, 0x00, 0x40, 0x05, 0x8c, 0x00, 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x40, 0x06, 0x10, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xba, 0x00, 0x40, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x40, 0x06, 0x10, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x40, 0x06, 0x50, 0x00, 0x00, 0x00, 0x38, 0x12, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x41, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x41, 0x10, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x40, 0x06, 0x00, 0x00, 0x00, 0x00, 0x08, 0x12, 0x02, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, 0x09, 0x10, 0x00, 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x41, 0x10, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x41, 0x10, 0x70, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x41, 0x10, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x40, 0x08, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x00, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x5f, 0x5f, 0x6c, 0x69, 0x62, 0x63, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x5f, 0x49, 0x54, 0x4d, 0x5f, 0x64, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x4d, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x5f, 0x49, 0x54, 0x4d, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x4d, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x5f, 0x5f, 0x64, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x00, 0x5f, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x00, 0x5f, 0x4a, 0x76, 0x5f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x00, 0x6c, 0x69, 0x62, 0x63, 0x2e, 0x73, 0x6f, 0x00, 0x5f, 0x44, 0x59, 0x4e, 0x41, 0x4d, 0x49, 0x43, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x49, 0x4e, 0x47, 0x00, 0x5f, 0x5f, 0x52, 0x4c, 0x44, 0x5f, 0x4d, 0x41, 0x50, 0x00, 0x5f, 0x66, 0x74, 0x65, 0x78, 0x74, 0x00, 0x5f, 0x66, 0x64, 0x61, 0x74, 0x61, 0x00, 0x5f, 0x65, 0x64, 0x61, 0x74, 0x61, 0x00, 0x5f, 0x5f, 0x62, 0x73, 0x73, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x5f, 0x66, 0x62, 0x73, 0x73, 0x00, 0x5f, 0x65, 0x6e, 0x64, 0x00, 0x5f, 0x5f, 0x67, 0x6e, 0x75, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x67, 0x70, 0x00, 0x5f, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x63, 0x00, 0x00, 0x00, 0x27, 0xbd, 0xff, 0xe0, 0xaf, 0xbc, 0x00, 0x18, 0xaf, 0xbf, 0x00, 0x1c, 0x04, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1c, 0x00, 0x42, 0x27, 0x9c, 0x90, 0x00, 0x8f, 0x99, 0x80, 0x24, 0x00, 0x00, 0x00, 0x00, 0x27, 0x39, 0x08, 0x0c, 0x04, 0x11, 0x00, 0x95, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xbc, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1c, 0x00, 0x42, 0x27, 0x9c, 0x90, 0x00, 0x8f, 0x99, 0x80, 0x24, 0x00, 0x00, 0x00, 0x00, 0x27, 0x39, 0x08, 0x90, 0x04, 0x11, 0x00, 0xab, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xbc, 0x00, 0x18, 0x8f, 0xbf, 0x00, 0x1c, 0x03, 0xe0, 0x00, 0x08, 0x27, 0xbd, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x08, 0x24, 0x02, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x11, 0x00, 0x04, 0x00, 0x00, 0xf0, 0x21, 0xff, 0xfe, 0x76, 0x18, 0xff, 0xfe, 0x76, 0x50, 0xff, 0xfe, 0x71, 0xc0, 0x8f, 0xfc, 0x00, 0x00, 0x03, 0xfc, 0xe0, 0x23, 0x03, 0xa0, 0x20, 0x21, 0x8f, 0xe5, 0x00, 0x08, 0x00, 0xbc, 0x28, 0x21, 0x8f, 0xf9, 0x00, 0x04, 0x03, 0x3c, 0xc8, 0x21, 0x24, 0x01, 0xff, 0xf8, 0x03, 0xa1, 0xe8, 0x24, 0x03, 0x20, 0xf8, 0x09, 0x27, 0xbd, 0xff, 0xf0, 0x3c, 0x1c, 0x00, 0x42, 0x27, 0x9c, 0x90, 0x00, 0x8f, 0x82, 0x80, 0x18, 0x27, 0xbd, 0xff, 0xd8, 0x8c, 0x85, 0x00, 0x00, 0x24, 0x86, 0x00, 0x04, 0x8f, 0x87, 0x80, 0x1c, 0x8f, 0x84, 0x80, 0x20, 0x8f, 0x99, 0x80, 0x38, 0xaf, 0xbf, 0x00, 0x24, 0xaf, 0xbc, 0x00, 0x18, 0xaf, 0xa0, 0x00, 0x14, 0x03, 0x20, 0xf8, 0x09, 0xaf, 0xa2, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x04, 0x00, 0x41, 0x3c, 0x02, 0x00, 0x41, 0x24, 0x84, 0x10, 0x04, 0x24, 0x42, 0x10, 0x07, 0x00, 0x44, 0x10, 0x23, 0x2c, 0x42, 0x00, 0x07, 0x14, 0x40, 0x00, 0x08, 0x3c, 0x1c, 0x00, 0x42, 0x27, 0x9c, 0x90, 0x00, 0x8f, 0x99, 0x80, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x13, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x04, 0x00, 0x41, 0x3c, 0x02, 0x00, 0x41, 0x24, 0x84, 0x10, 0x04, 0x24, 0x42, 0x10, 0x04, 0x00, 0x44, 0x10, 0x23, 0x00, 0x02, 0x10, 0x83, 0x00, 0x02, 0x2f, 0xc2, 0x00, 0xa2, 0x28, 0x21, 0x00, 0x05, 0x28, 0x43, 0x10, 0xa0, 0x00, 0x08, 0x3c, 0x1c, 0x00, 0x42, 0x27, 0x9c, 0x90, 0x00, 0x8f, 0x99, 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x13, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x27, 0xbd, 0xff, 0xd0, 0xaf, 0xb3, 0x00, 0x28, 0x3c, 0x13, 0x00, 0x41, 0x3c, 0x1c, 0x00, 0x42, 0x92, 0x62, 0x10, 0x50, 0x27, 0x9c, 0x90, 0x00, 0xaf, 0xbf, 0x00, 0x2c, 0xaf, 0xb2, 0x00, 0x24, 0xaf, 0xb1, 0x00, 0x20, 0xaf, 0xb0, 0x00, 0x1c, 0x14, 0x40, 0x00, 0x28, 0xaf, 0xbc, 0x00, 0x10, 0x3c, 0x11, 0x00, 0x41, 0x3c, 0x02, 0x00, 0x41, 0x24, 0x42, 0x0f, 0xf8, 0x26, 0x31, 0x0f, 0xf4, 0x00, 0x51, 0x88, 0x23, 0x3c, 0x10, 0x00, 0x41, 0x8e, 0x02, 0x10, 0x54, 0x00, 0x11, 0x88, 0x83, 0x26, 0x31, 0xff, 0xff, 0x3c, 0x04, 0x00, 0x41, 0x00, 0x51, 0x18, 0x2b, 0x24, 0x92, 0x0f, 0xf4, 0x10, 0x60, 0x00, 0x0c, 0x24, 0x42, 0x00, 0x01, 0x00, 0x02, 0x18, 0x80, 0x02, 0x43, 0x18, 0x21, 0x8c, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0xf8, 0x09, 0xae, 0x02, 0x10, 0x54, 0x8e, 0x02, 0x10, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x18, 0x2b, 0x14, 0x60, 0xff, 0xf6, 0x24, 0x42, 0x00, 0x01, 0x0c, 0x10, 0x01, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xbc, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x82, 0x80, 0x44, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x06, 0x24, 0x02, 0x00, 0x01, 0x8f, 0x99, 0x80, 0x44, 0x3c, 0x04, 0x00, 0x40, 0x03, 0x20, 0xf8, 0x09, 0x24, 0x84, 0x09, 0x58, 0x24, 0x02, 0x00, 0x01, 0xa2, 0x62, 0x10, 0x50, 0x8f, 0xbf, 0x00, 0x2c, 0x8f, 0xb3, 0x00, 0x28, 0x8f, 0xb2, 0x00, 0x24, 0x8f, 0xb1, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x1c, 0x03, 0xe0, 0x00, 0x08, 0x27, 0xbd, 0x00, 0x30, 0x3c, 0x1c, 0x00, 0x42, 0x27, 0x9c, 0x90, 0x00, 0x8f, 0x82, 0x80, 0x30, 0x27, 0xbd, 0xff, 0xe0, 0xaf, 0xbf, 0x00, 0x1c, 0x10, 0x40, 0x00, 0x08, 0xaf, 0xbc, 0x00, 0x10, 0x8f, 0x99, 0x80, 0x30, 0x3c, 0x05, 0x00, 0x41, 0x3c, 0x04, 0x00, 0x40, 0x24, 0xa5, 0x10, 0x58, 0x03, 0x20, 0xf8, 0x09, 0x24, 0x84, 0x09, 0x58, 0x8f, 0xbc, 0x00, 0x10, 0x3c, 0x02, 0x00, 0x41, 0x24, 0x44, 0x0f, 0xfc, 0x8c, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x40, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xbf, 0x00, 0x1c, 0x08, 0x10, 0x01, 0xb5, 0x27, 0xbd, 0x00, 0x20, 0x8f, 0x99, 0x80, 0x34, 0x00, 0x00, 0x00, 0x00, 0x13, 0x20, 0xff, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, 0xf8, 0x09, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xbc, 0x00, 0x10, 0x10, 0x00, 0xff, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x00, 0x41, 0x8c, 0x59, 0x0f, 0xec, 0x24, 0x02, 0xff, 0xff, 0x13, 0x22, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x27, 0xbd, 0xff, 0xd8, 0xaf, 0xb0, 0x00, 0x1c, 0x3c, 0x10, 0x00, 0x41, 0xaf, 0xb1, 0x00, 0x20, 0xaf, 0xbf, 0x00, 0x24, 0x26, 0x10, 0x0f, 0xec, 0x24, 0x11, 0xff, 0xff, 0x03, 0x20, 0xf8, 0x09, 0x26, 0x10, 0xff, 0xfc, 0x8e, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x31, 0xff, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xbf, 0x00, 0x24, 0x8f, 0xb1, 0x00, 0x20, 0x8f, 0xb0, 0x00, 0x1c, 0x27, 0xbd, 0x00, 0x28, 0x03, 0xe0, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x99, 0x80, 0x10, 0x03, 0xe0, 0x78, 0x21, 0x03, 0x20, 0xf8, 0x09, 0x24, 0x18, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0xbd, 0xff, 0xe0, 0xaf, 0xbc, 0x00, 0x18, 0xaf, 0xbf, 0x00, 0x1c, 0x04, 0x11, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1c, 0x00, 0x42, 0x27, 0x9c, 0x90, 0x00, 0x8f, 0x99, 0x80, 0x24, 0x00, 0x00, 0x00, 0x00, 0x27, 0x39, 0x07, 0x24, 0x04, 0x11, 0xff, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xbc, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xbc, 0x00, 0x18, 0x8f, 0xbf, 0x00, 0x1c, 0x03, 0xe0, 0x00, 0x08, 0x27, 0xbd, 0x00, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x40, 0x09, 0x10, 0x00, 0x40, 0x05, 0x8c, 0x00, 0x40, 0x06, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x43, 0x43, 0x3a, 0x20, 0x28, 0x47, 0x4e, 0x55, 0x29, 0x20, 0x35, 0x2e, 0x33, 0x2e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x50, 0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x40, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x02, 0x00, 0x00, 0x00, 0xa3, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x8c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x40, 0x09, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x02, 0x00, 0x00, 0x01, 0x13, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xe8, 0x00, 0x00, 0x00, 0x10, 0x00, 0x40, 0x09, 0x48, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x0c, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x01, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0d, 0x00, 0x40, 0x06, 0x50, 0x00, 0x00, 0x00, 0x38, 0x01, 0x9c, 0x00, 0x00, 0x00, 0x7b, 0x03, 0x70, 0x00, 0x01, 0x0d, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x01, 0x0f, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x2e, 0x04, 0x00, 0x00, 0x01, 0x49, 0x01, 0x10, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x4d, 0x05, 0x00, 0x40, 0x06, 0x88, 0x06, 0x01, 0x56, 0x05, 0xf3, 0x01, 0x54, 0x23, 0x04, 0x06, 0x02, 0x8d, 0x14, 0x01, 0x30, 0x00, 0x00, 0x07, 0x04, 0x00, 0x00, 0x00, 0x81, 0x08, 0x04, 0x05, 0x00, 0x00, 0x00, 0xf4, 0x09, 0x04, 0x05, 0x69, 0x6e, 0x74, 0x00, 0x07, 0x04, 0x00, 0x00, 0x00, 0x95, 0x07, 0x04, 0x00, 0x00, 0x00, 0x9b, 0x08, 0x01, 0x06, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x83, 0x04, 0x01, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x10, 0x63, 0x72, 0x74, 0x2f, 0x6d, 0x69, 0x70, 0x73, 0x2f, 0x63, 0x72, 0x74, 0x69, 0x2e, 0x73, 0x00, 0x2f, 0x68, 0x6f, 0x6d, 0x65, 0x2f, 0x61, 0x6c, 0x62, 0x69, 0x6e, 0x6f, 0x6c, 0x6f, 0x62, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x2f, 0x6d, 0x75, 0x73, 0x6c, 0x2d, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x2d, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x6d, 0x75, 0x73, 0x6c, 0x2d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x36, 0x00, 0x47, 0x4e, 0x55, 0x20, 0x41, 0x53, 0x20, 0x32, 0x2e, 0x32, 0x35, 0x2e, 0x31, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x95, 0x04, 0x01, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x30, 0x63, 0x72, 0x74, 0x2f, 0x6d, 0x69, 0x70, 0x73, 0x2f, 0x63, 0x72, 0x74, 0x6e, 0x2e, 0x73, 0x00, 0x2f, 0x68, 0x6f, 0x6d, 0x65, 0x2f, 0x61, 0x6c, 0x62, 0x69, 0x6e, 0x6f, 0x6c, 0x6f, 0x62, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x2f, 0x6d, 0x75, 0x73, 0x6c, 0x2d, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x2d, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x6d, 0x75, 0x73, 0x6c, 0x2d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x36, 0x00, 0x47, 0x4e, 0x55, 0x20, 0x41, 0x53, 0x20, 0x32, 0x2e, 0x32, 0x35, 0x2e, 0x31, 0x00, 0x80, 0x01, 0x01, 0x11, 0x01, 0x25, 0x0e, 0x13, 0x0b, 0x03, 0x0e, 0x1b, 0x0e, 0x55, 0x17, 0x11, 0x01, 0x10, 0x17, 0x00, 0x00, 0x02, 0x2e, 0x01, 0x3f, 0x19, 0x03, 0x0e, 0x3a, 0x0b, 0x3b, 0x0b, 0x27, 0x19, 0x87, 0x01, 0x19, 0x11, 0x01, 0x12, 0x06, 0x40, 0x18, 0x97, 0x42, 0x19, 0x01, 0x13, 0x00, 0x00, 0x03, 0x05, 0x00, 0x03, 0x08, 0x3a, 0x0b, 0x3b, 0x0b, 0x49, 0x13, 0x02, 0x17, 0x00, 0x00, 0x04, 0x34, 0x00, 0x03, 0x0e, 0x3a, 0x0b, 0x3b, 0x0b, 0x49, 0x13, 0x02, 0x17, 0x00, 0x00, 0x05, 0x89, 0x82, 0x01, 0x01, 0x11, 0x01, 0x00, 0x00, 0x06, 0x8a, 0x82, 0x01, 0x00, 0x02, 0x18, 0x91, 0x42, 0x18, 0x00, 0x00, 0x07, 0x0f, 0x00, 0x0b, 0x0b, 0x49, 0x13, 0x00, 0x00, 0x08, 0x24, 0x00, 0x0b, 0x0b, 0x3e, 0x0b, 0x03, 0x0e, 0x00, 0x00, 0x09, 0x24, 0x00, 0x0b, 0x0b, 0x3e, 0x0b, 0x03, 0x08, 0x00, 0x00, 0x00, 0x01, 0x11, 0x00, 0x10, 0x06, 0x55, 0x06, 0x03, 0x08, 0x1b, 0x08, 0x25, 0x08, 0x13, 0x05, 0x00, 0x00, 0x00, 0x01, 0x11, 0x00, 0x10, 0x06, 0x55, 0x06, 0x03, 0x08, 0x1b, 0x08, 0x25, 0x08, 0x13, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x01, 0x01, 0xfb, 0x0e, 0x0d, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x63, 0x72, 0x74, 0x00, 0x00, 0x63, 0x72, 0x74, 0x31, 0x2e, 0x63, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x02, 0x00, 0x40, 0x06, 0x50, 0x03, 0x0d, 0x01, 0x85, 0x47, 0x4d, 0x08, 0x39, 0x4a, 0x4d, 0x02, 0x0c, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x26, 0x01, 0x01, 0xfb, 0x0e, 0x0d, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x63, 0x72, 0x74, 0x2f, 0x6d, 0x69, 0x70, 0x73, 0x00, 0x00, 0x63, 0x72, 0x74, 0x69, 0x2e, 0x73, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x02, 0x00, 0x40, 0x05, 0x8c, 0x19, 0x4b, 0x4b, 0x02, 0x04, 0x00, 0x01, 0x01, 0x00, 0x05, 0x02, 0x00, 0x40, 0x09, 0x10, 0x03, 0x10, 0x01, 0x4b, 0x4b, 0x02, 0x04, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x02, 0x00, 0x00, 0x00, 0x26, 0x01, 0x01, 0xfb, 0x0e, 0x0d, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x63, 0x72, 0x74, 0x2f, 0x6d, 0x69, 0x70, 0x73, 0x00, 0x00, 0x63, 0x72, 0x74, 0x6e, 0x2e, 0x73, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x05, 0x02, 0x00, 0x40, 0x05, 0xe8, 0x15, 0x4b, 0x4b, 0x4b, 0x02, 0x04, 0x00, 0x01, 0x01, 0x00, 0x05, 0x02, 0x00, 0x40, 0x09, 0x48, 0x03, 0x09, 0x01, 0x4b, 0x4b, 0x4b, 0x02, 0x04, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x01, 0x7c, 0x1f, 0x0d, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x50, 0x00, 0x00, 0x00, 0x38, 0x50, 0x0e, 0x28, 0x58, 0x9f, 0x01, 0x00, 0x00, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x63, 0x00, 0x61, 0x72, 0x67, 0x63, 0x00, 0x47, 0x4e, 0x55, 0x20, 0x43, 0x39, 0x39, 0x20, 0x35, 0x2e, 0x33, 0x2e, 0x30, 0x20, 0x2d, 0x6d, 0x65, 0x62, 0x20, 0x2d, 0x6d, 0x6c, 0x6c, 0x73, 0x63, 0x20, 0x2d, 0x6d, 0x6e, 0x6f, 0x2d, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x20, 0x2d, 0x6d, 0x61, 0x62, 0x69, 0x3d, 0x33, 0x32, 0x20, 0x2d, 0x67, 0x20, 0x2d, 0x4f, 0x73, 0x20, 0x2d, 0x73, 0x74, 0x64, 0x3d, 0x63, 0x39, 0x39, 0x20, 0x2d, 0x66, 0x66, 0x72, 0x65, 0x65, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x2d, 0x66, 0x65, 0x78, 0x63, 0x65, 0x73, 0x73, 0x2d, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x2d, 0x66, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x2d, 0x6d, 0x61, 0x74, 0x68, 0x20, 0x2d, 0x66, 0x6e, 0x6f, 0x2d, 0x75, 0x6e, 0x77, 0x69, 0x6e, 0x64, 0x2d, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x20, 0x2d, 0x66, 0x6e, 0x6f, 0x2d, 0x61, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x6f, 0x75, 0x73, 0x2d, 0x75, 0x6e, 0x77, 0x69, 0x6e, 0x64, 0x2d, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x20, 0x2d, 0x66, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x2d, 0x66, 0x64, 0x61, 0x74, 0x61, 0x2d, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x2d, 0x66, 0x6e, 0x6f, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2d, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x00, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x69, 0x6e, 0x74, 0x00, 0x63, 0x72, 0x74, 0x2f, 0x63, 0x72, 0x74, 0x31, 0x2e, 0x63, 0x00, 0x63, 0x68, 0x61, 0x72, 0x00, 0x2f, 0x68, 0x6f, 0x6d, 0x65, 0x2f, 0x61, 0x6c, 0x62, 0x69, 0x6e, 0x6f, 0x6c, 0x6f, 0x62, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x2f, 0x6d, 0x75, 0x73, 0x6c, 0x2d, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x2d, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x6d, 0x75, 0x73, 0x6c, 0x2d, 0x31, 0x2e, 0x31, 0x2e, 0x31, 0x36, 0x00, 0x61, 0x72, 0x67, 0x76, 0x00, 0x00, 0x40, 0x06, 0x50, 0x00, 0x40, 0x06, 0x70, 0x00, 0x01, 0x54, 0x00, 0x40, 0x06, 0x70, 0x00, 0x40, 0x06, 0x87, 0x00, 0x03, 0x76, 0x7c, 0x9f, 0x00, 0x40, 0x06, 0x87, 0x00, 0x40, 0x06, 0x88, 0x00, 0x04, 0xf3, 0x01, 0x54, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x50, 0x00, 0x40, 0x06, 0x70, 0x00, 0x02, 0x74, 0x00, 0x00, 0x40, 0x06, 0x70, 0x00, 0x40, 0x06, 0x87, 0x00, 0x01, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x50, 0x00, 0x40, 0x06, 0x68, 0x00, 0x03, 0x74, 0x04, 0x9f, 0x00, 0x40, 0x06, 0x68, 0x00, 0x40, 0x06, 0x87, 0x00, 0x01, 0x56, 0x00, 0x40, 0x06, 0x87, 0x00, 0x40, 0x06, 0x88, 0x00, 0x06, 0xf3, 0x01, 0x54, 0x23, 0x04, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x50, 0x00, 0x40, 0x06, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x8c, 0x00, 0x40, 0x05, 0x98, 0x00, 0x40, 0x09, 0x10, 0x00, 0x40, 0x09, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0xe8, 0x00, 0x40, 0x05, 0xf8, 0x00, 0x40, 0x09, 0x48, 0x00, 0x40, 0x09, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x0f, 0x67, 0x6e, 0x75, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x04, 0x01, 0x00, 0x2e, 0x73, 0x79, 0x6d, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x73, 0x68, 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x00, 0x2e, 0x4d, 0x49, 0x50, 0x53, 0x2e, 0x61, 0x62, 0x69, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x00, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x6e, 0x66, 0x6f, 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x00, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x73, 0x79, 0x6d, 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x73, 0x74, 0x72, 0x00, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x00, 0x2e, 0x4d, 0x49, 0x50, 0x53, 0x2e, 0x73, 0x74, 0x75, 0x62, 0x73, 0x00, 0x2e, 0x66, 0x69, 0x6e, 0x69, 0x00, 0x2e, 0x65, 0x68, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x00, 0x2e, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x00, 0x2e, 0x64, 0x74, 0x6f, 0x72, 0x73, 0x00, 0x2e, 0x6a, 0x63, 0x72, 0x00, 0x2e, 0x72, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x70, 0x00, 0x2e, 0x67, 0x6f, 0x74, 0x00, 0x2e, 0x73, 0x64, 0x61, 0x74, 0x61, 0x00, 0x2e, 0x62, 0x73, 0x73, 0x00, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x2e, 0x70, 0x64, 0x72, 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x61, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x61, 0x62, 0x62, 0x72, 0x65, 0x76, 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x73, 0x74, 0x72, 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x6c, 0x6f, 0x63, 0x00, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x00, 0x2e, 0x67, 0x6e, 0x75, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x00, 0x2e, 0x6d, 0x64, 0x65, 0x62, 0x75, 0x67, 0x2e, 0x61, 0x62, 0x69, 0x33, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x74, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x90, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x03, 0x24, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0x84, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x08, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x09, 0x10, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x09, 0x58, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0f, 0xec, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0f, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x10, 0x48, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x10, 0x50, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xf1, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xf1, 0x00, 0x00, 0x00, 0x17, 0x00, 0x41, 0x0f, 0xec, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x25, 0x00, 0x41, 0x0f, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x33, 0x00, 0x40, 0x09, 0x58, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x46, 0x00, 0x41, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x53, 0x00, 0x40, 0x06, 0x90, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x68, 0x00, 0x40, 0x06, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x40, 0x07, 0x24, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x91, 0x00, 0x41, 0x10, 0x50, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x41, 0x10, 0x54, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xae, 0x00, 0x40, 0x08, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xba, 0x00, 0x41, 0x10, 0x58, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xf1, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x41, 0x0f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x40, 0x09, 0x58, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x41, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xed, 0x00, 0x40, 0x08, 0x90, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x09, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xf1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xff, 0xf1, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x40, 0x08, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x01, 0x17, 0x00, 0x40, 0x01, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x01, 0x20, 0x00, 0x41, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xf1, 0x00, 0x00, 0x01, 0x24, 0x00, 0x41, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x30, 0x00, 0x41, 0x0f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x01, 0x3d, 0x00, 0x41, 0x10, 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x12, 0x00, 0x00, 0x01, 0x4a, 0x00, 0x41, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x11, 0x00, 0x00, 0x01, 0x60, 0x00, 0x41, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x76, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0xff, 0xf1, 0x00, 0x00, 0x01, 0x87, 0x00, 0x40, 0x05, 0x8c, 0x00, 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xa5, 0x00, 0x40, 0x06, 0x10, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x09, 0x00, 0x00, 0x01, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc7, 0x00, 0x40, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x09, 0x00, 0x00, 0x01, 0xce, 0x00, 0x40, 0x06, 0x10, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x09, 0x00, 0x00, 0x01, 0xd5, 0x00, 0x40, 0x06, 0x50, 0x00, 0x00, 0x00, 0x38, 0x12, 0x00, 0x00, 0x09, 0x00, 0x00, 0x01, 0xde, 0x00, 0x41, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x04, 0x00, 0x41, 0x10, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x13, 0x00, 0x00, 0x02, 0x10, 0x00, 0x40, 0x06, 0x00, 0x00, 0x00, 0x00, 0x08, 0x12, 0x02, 0x00, 0x09, 0x00, 0x00, 0x02, 0x15, 0x00, 0x40, 0x09, 0x10, 0x00, 0x00, 0x00, 0x08, 0x12, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x02, 0x1b, 0x00, 0x41, 0x10, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x02, 0x22, 0x00, 0x41, 0x10, 0x70, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x13, 0x00, 0x00, 0x02, 0x27, 0x00, 0x40, 0x08, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x4d, 0x00, 0x41, 0x10, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x13, 0x00, 0x00, 0x02, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x63, 0x72, 0x74, 0x2f, 0x63, 0x72, 0x74, 0x31, 0x2e, 0x63, 0x00, 0x63, 0x72, 0x74, 0x73, 0x74, 0x75, 0x66, 0x66, 0x2e, 0x63, 0x00, 0x5f, 0x5f, 0x43, 0x54, 0x4f, 0x52, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x44, 0x54, 0x4f, 0x52, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x45, 0x48, 0x5f, 0x46, 0x52, 0x41, 0x4d, 0x45, 0x5f, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x4a, 0x43, 0x52, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x5f, 0x00, 0x64, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x74, 0x6d, 0x5f, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x73, 0x00, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x74, 0x6d, 0x5f, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x73, 0x00, 0x5f, 0x5f, 0x64, 0x6f, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x64, 0x74, 0x6f, 0x72, 0x73, 0x5f, 0x61, 0x75, 0x78, 0x00, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x2e, 0x33, 0x35, 0x31, 0x35, 0x00, 0x64, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x78, 0x2e, 0x33, 0x35, 0x31, 0x37, 0x00, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x00, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x33, 0x35, 0x32, 0x37, 0x00, 0x5f, 0x5f, 0x43, 0x54, 0x4f, 0x52, 0x5f, 0x45, 0x4e, 0x44, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x46, 0x52, 0x41, 0x4d, 0x45, 0x5f, 0x45, 0x4e, 0x44, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x4a, 0x43, 0x52, 0x5f, 0x45, 0x4e, 0x44, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x64, 0x6f, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x5f, 0x61, 0x75, 0x78, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x63, 0x00, 0x5f, 0x4d, 0x49, 0x50, 0x53, 0x5f, 0x53, 0x54, 0x55, 0x42, 0x53, 0x5f, 0x00, 0x5f, 0x44, 0x59, 0x4e, 0x41, 0x4d, 0x49, 0x43, 0x00, 0x5f, 0x67, 0x70, 0x00, 0x5f, 0x5f, 0x54, 0x4d, 0x43, 0x5f, 0x45, 0x4e, 0x44, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x44, 0x54, 0x4f, 0x52, 0x5f, 0x45, 0x4e, 0x44, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x64, 0x73, 0x6f, 0x5f, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x00, 0x5f, 0x47, 0x4c, 0x4f, 0x42, 0x41, 0x4c, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0x5f, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x00, 0x5f, 0x66, 0x64, 0x61, 0x74, 0x61, 0x00, 0x5f, 0x5f, 0x67, 0x6e, 0x75, 0x5f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x67, 0x70, 0x00, 0x5f, 0x44, 0x59, 0x4e, 0x41, 0x4d, 0x49, 0x43, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x49, 0x4e, 0x47, 0x00, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x5f, 0x5f, 0x64, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x00, 0x5f, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x5f, 0x49, 0x54, 0x4d, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x4d, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x5f, 0x66, 0x74, 0x65, 0x78, 0x74, 0x00, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x63, 0x00, 0x5f, 0x5f, 0x52, 0x4c, 0x44, 0x5f, 0x4d, 0x41, 0x50, 0x00, 0x5f, 0x49, 0x54, 0x4d, 0x5f, 0x64, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x4d, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x5f, 0x5f, 0x62, 0x73, 0x73, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x00, 0x5f, 0x65, 0x64, 0x61, 0x74, 0x61, 0x00, 0x5f, 0x65, 0x6e, 0x64, 0x00, 0x5f, 0x5f, 0x6c, 0x69, 0x62, 0x63, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x5f, 0x4a, 0x76, 0x5f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x00, 0x5f, 0x66, 0x62, 0x73, 0x73, 0x00, 0x5f, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x01, 0x74, 0x00, 0x00, 0x01, 0x74, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x70, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x01, 0x90, 0x00, 0x00, 0x01, 0x90, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x32, 0x70, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x01, 0xa8, 0x00, 0x00, 0x01, 0xa8, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x01, 0xc0, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x02, 0x80, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x03, 0x24, 0x00, 0x00, 0x03, 0x24, 0x00, 0x00, 0x01, 0x60, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x04, 0x84, 0x00, 0x00, 0x04, 0x84, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x40, 0x05, 0x8c, 0x00, 0x00, 0x05, 0x8c, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x40, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x40, 0x08, 0xf0, 0x00, 0x00, 0x08, 0xf0, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x40, 0x09, 0x10, 0x00, 0x00, 0x09, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x40, 0x09, 0x58, 0x00, 0x00, 0x09, 0x58, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x41, 0x0f, 0xec, 0x00, 0x00, 0x0f, 0xec, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x41, 0x0f, 0xf4, 0x00, 0x00, 0x0f, 0xf4, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x41, 0x0f, 0xfc, 0x00, 0x00, 0x0f, 0xfc, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x41, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x03, 0x00, 0x41, 0x10, 0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x03, 0x00, 0x41, 0x10, 0x48, 0x00, 0x00, 0x10, 0x48, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x41, 0x10, 0x50, 0x00, 0x00, 0x10, 0x4c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x4c, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x60, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x70, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x70, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x10, 0x00, 0x00, 0x01, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x70, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x93, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x70, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x3a, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x70, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x20, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x70, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x48, 0x00, 0x00, 0x01, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x0a, 0x70, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x96, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x15, 0x70, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x18, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x23, 0x6f, 0xff, 0xff, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x68, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x33, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x78, 0x00, 0x00, 0x01, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0xbc, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xbc, 0x00, 0x00, 0x02, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 }; unsigned char ELF_x64_FILE[] = { 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x07, 0x00, 0x40, 0x00, 0x16, 0x00, 0x13, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x78, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x90, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0xe5, 0x74, 0x64, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x52, 0xe5, 0x74, 0x64, 0x04, 0x00, 0x00, 0x00, 0x78, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x6c, 0x64, 0x2d, 0x6d, 0x75, 0x73, 0x6c, 0x2d, 0x78, 0x38, 0x36, 0x5f, 0x36, 0x34, 0x2e, 0x73, 0x6f, 0x2e, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 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, 0x33, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0xd8, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08, 0x00, 0x06, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x10, 0x00, 0x11, 0x00, 0x28, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x09, 0x00, 0xf6, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x28, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x10, 0x00, 0x11, 0x00, 0x30, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x69, 0x62, 0x63, 0x2e, 0x73, 0x6f, 0x00, 0x5f, 0x5f, 0x6c, 0x69, 0x62, 0x63, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x5f, 0x65, 0x64, 0x61, 0x74, 0x61, 0x00, 0x5f, 0x5f, 0x62, 0x73, 0x73, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x5f, 0x65, 0x6e, 0x64, 0x00, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x5f, 0x49, 0x54, 0x4d, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x4d, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x5f, 0x49, 0x54, 0x4d, 0x5f, 0x64, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x4d, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x00, 0x5f, 0x4a, 0x76, 0x5f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x58, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x35, 0x22, 0x0c, 0x20, 0x00, 0xff, 0x25, 0x24, 0x0c, 0x20, 0x00, 0x0f, 0x1f, 0x40, 0x00, 0xff, 0x25, 0x22, 0x0c, 0x20, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0xe9, 0xe0, 0xff, 0xff, 0xff, 0xb8, 0x2a, 0x00, 0x00, 0x00, 0xc3, 0x48, 0x31, 0xed, 0x49, 0x89, 0xd1, 0x5e, 0x48, 0x89, 0xe2, 0x48, 0x83, 0xe4, 0xf0, 0x49, 0xc7, 0xc0, 0xf6, 0x04, 0x40, 0x00, 0x48, 0xc7, 0xc1, 0xd8, 0x03, 0x40, 0x00, 0x48, 0xc7, 0xc7, 0x00, 0x04, 0x40, 0x00, 0xe8, 0xc2, 0xff, 0xff, 0xff, 0xeb, 0xfe, 0xb8, 0x2f, 0x10, 0x60, 0x00, 0x55, 0x48, 0x2d, 0x28, 0x10, 0x60, 0x00, 0x48, 0x83, 0xf8, 0x0e, 0x48, 0x89, 0xe5, 0x76, 0x1b, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x74, 0x11, 0x5d, 0xbf, 0x28, 0x10, 0x60, 0x00, 0xff, 0xe0, 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0xc3, 0x0f, 0x1f, 0x40, 0x00, 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x28, 0x10, 0x60, 0x00, 0x55, 0x48, 0x81, 0xee, 0x28, 0x10, 0x60, 0x00, 0x48, 0xc1, 0xfe, 0x03, 0x48, 0x89, 0xe5, 0x48, 0x89, 0xf0, 0x48, 0xc1, 0xe8, 0x3f, 0x48, 0x01, 0xc6, 0x48, 0xd1, 0xfe, 0x74, 0x15, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x74, 0x0b, 0x5d, 0xbf, 0x28, 0x10, 0x60, 0x00, 0xff, 0xe0, 0x0f, 0x1f, 0x00, 0x5d, 0xc3, 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00, 0x80, 0x3d, 0x71, 0x0b, 0x20, 0x00, 0x00, 0x75, 0x11, 0x55, 0x48, 0x89, 0xe5, 0xe8, 0x6e, 0xff, 0xff, 0xff, 0x5d, 0xc6, 0x05, 0x5e, 0x0b, 0x20, 0x00, 0x01, 0xf3, 0xc3, 0x0f, 0x1f, 0x40, 0x00, 0xbf, 0x88, 0x0e, 0x60, 0x00, 0x48, 0x83, 0x3f, 0x00, 0x75, 0x05, 0xeb, 0x93, 0x0f, 0x1f, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x74, 0xf1, 0x55, 0x48, 0x89, 0xe5, 0xff, 0xd0, 0x5d, 0xe9, 0x7a, 0xff, 0xff, 0xff, 0x50, 0x58, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x43, 0x43, 0x3a, 0x20, 0x28, 0x55, 0x62, 0x75, 0x6e, 0x74, 0x75, 0x20, 0x35, 0x2e, 0x34, 0x2e, 0x30, 0x2d, 0x36, 0x75, 0x62, 0x75, 0x6e, 0x74, 0x75, 0x31, 0x7e, 0x31, 0x36, 0x2e, 0x30, 0x34, 0x2e, 0x34, 0x29, 0x20, 0x35, 0x2e, 0x34, 0x2e, 0x30, 0x20, 0x32, 0x30, 0x31, 0x36, 0x30, 0x36, 0x30, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0xc8, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0xe8, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x28, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x30, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x00, 0xc0, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00, 0xd8, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x07, 0x00, 0xe0, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x09, 0x00, 0xf6, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x00, 0x05, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x78, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x80, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0d, 0x00, 0x88, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x90, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x00, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, 0x20, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x11, 0x00, 0x28, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0xf1, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x88, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x30, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x70, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0xb0, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x11, 0x00, 0x28, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x80, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0xd0, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x78, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x04, 0x00, 0xf1, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0xf1, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x00, 0x05, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x88, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0xf1, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x90, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x28, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x20, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x01, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x00, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0xd8, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x10, 0x00, 0x08, 0x00, 0x06, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x01, 0x00, 0x00, 0x10, 0x00, 0x11, 0x00, 0x28, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x01, 0x00, 0x00, 0x10, 0x00, 0x09, 0x00, 0xf6, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x28, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x01, 0x00, 0x00, 0x10, 0x00, 0x11, 0x00, 0x30, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x01, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x72, 0x74, 0x73, 0x74, 0x75, 0x66, 0x66, 0x2e, 0x63, 0x00, 0x5f, 0x5f, 0x4a, 0x43, 0x52, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x5f, 0x00, 0x64, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x74, 0x6d, 0x5f, 0x63, 0x6c, 0x6f, 0x6e, 0x65, 0x73, 0x00, 0x5f, 0x5f, 0x64, 0x6f, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x64, 0x74, 0x6f, 0x72, 0x73, 0x5f, 0x61, 0x75, 0x78, 0x00, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x2e, 0x37, 0x35, 0x38, 0x35, 0x00, 0x5f, 0x5f, 0x64, 0x6f, 0x5f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x64, 0x74, 0x6f, 0x72, 0x73, 0x5f, 0x61, 0x75, 0x78, 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x00, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x00, 0x5f, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x5f, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x63, 0x00, 0x5f, 0x5f, 0x46, 0x52, 0x41, 0x4d, 0x45, 0x5f, 0x45, 0x4e, 0x44, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x4a, 0x43, 0x52, 0x5f, 0x45, 0x4e, 0x44, 0x5f, 0x5f, 0x00, 0x5f, 0x44, 0x59, 0x4e, 0x41, 0x4d, 0x49, 0x43, 0x00, 0x5f, 0x5f, 0x54, 0x4d, 0x43, 0x5f, 0x45, 0x4e, 0x44, 0x5f, 0x5f, 0x00, 0x5f, 0x5f, 0x64, 0x73, 0x6f, 0x5f, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x00, 0x5f, 0x47, 0x4c, 0x4f, 0x42, 0x41, 0x4c, 0x5f, 0x4f, 0x46, 0x46, 0x53, 0x45, 0x54, 0x5f, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x00, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x5f, 0x49, 0x54, 0x4d, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x4d, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x5f, 0x49, 0x54, 0x4d, 0x5f, 0x64, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x54, 0x4d, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x00, 0x5f, 0x5f, 0x62, 0x73, 0x73, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x5f, 0x66, 0x69, 0x6e, 0x69, 0x00, 0x5f, 0x65, 0x64, 0x61, 0x74, 0x61, 0x00, 0x5f, 0x65, 0x6e, 0x64, 0x00, 0x5f, 0x5f, 0x6c, 0x69, 0x62, 0x63, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x5f, 0x4a, 0x76, 0x5f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x65, 0x73, 0x00, 0x00, 0x2e, 0x73, 0x79, 0x6d, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x73, 0x68, 0x73, 0x74, 0x72, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x00, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x73, 0x79, 0x6d, 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x73, 0x74, 0x72, 0x00, 0x2e, 0x72, 0x65, 0x6c, 0x61, 0x2e, 0x70, 0x6c, 0x74, 0x00, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x00, 0x2e, 0x74, 0x65, 0x78, 0x74, 0x00, 0x2e, 0x66, 0x69, 0x6e, 0x69, 0x00, 0x2e, 0x65, 0x68, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x00, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x00, 0x2e, 0x66, 0x69, 0x6e, 0x69, 0x5f, 0x61, 0x72, 0x72, 0x61, 0x79, 0x00, 0x2e, 0x6a, 0x63, 0x72, 0x00, 0x2e, 0x64, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x00, 0x2e, 0x67, 0x6f, 0x74, 0x2e, 0x70, 0x6c, 0x74, 0x00, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x00, 0x2e, 0x62, 0x73, 0x73, 0x00, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 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, 0x23, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 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, 0x39, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 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, 0x3e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 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, 0x4f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 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, 0x55, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x0e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 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, 0x99, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa2, 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, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x01, 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 }; uint8_t MACHO_X86_FILE[] = { 0xce, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x24, 0x04, 0x00, 0x00, 0x85, 0x00, 0x20, 0x01, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x50, 0x41, 0x47, 0x45, 0x5a, 0x45, 0x52, 0x4f, 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, 0x01, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x1e, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x90, 0x0e, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x5f, 0x73, 0x74, 0x75, 0x62, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x1f, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x36, 0x0f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x05, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x73, 0x74, 0x75, 0x62, 0x5f, 0x68, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x1f, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x44, 0x0f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x1f, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x64, 0x0f, 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, 0x5f, 0x5f, 0x75, 0x6e, 0x77, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x1f, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xac, 0x0f, 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, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x6e, 0x6c, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x5f, 0x70, 0x74, 0x72, 0x00, 0x5f, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x6c, 0x61, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x5f, 0x70, 0x74, 0x72, 0x00, 0x5f, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x20, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x45, 0x44, 0x49, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x20, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x20, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x44, 0x20, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x88, 0x20, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xdc, 0x20, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x20, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x64, 0x79, 0x6c, 0x64, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x5f, 0xb5, 0x95, 0x0f, 0x40, 0x25, 0x3d, 0x4f, 0xa8, 0xfb, 0x96, 0x48, 0xc1, 0x74, 0x07, 0x90, 0x24, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0a, 0x00, 0x00, 0x0a, 0x0a, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x80, 0x18, 0x00, 0x00, 0x00, 0x90, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x04, 0x00, 0x00, 0x01, 0x00, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x6c, 0x69, 0x62, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x42, 0x2e, 0x64, 0x79, 0x6c, 0x69, 0x62, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x20, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x74, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x74, 0x20, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t MACHO_PPC_FILE[] = { 0xfe, 0xed, 0xfa, 0xce, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x05, 0xcc, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x38, 0x5f, 0x5f, 0x50, 0x41, 0x47, 0x45, 0x5a, 0x45, 0x52, 0x4f, 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, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x14, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0xb8, 0x00, 0x00, 0xb8, 0x38, 0x00, 0x00, 0x0e, 0xb8, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x70, 0x69, 0x63, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x5f, 0x73, 0x74, 0x75, 0x62, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x5f, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x5f, 0x73, 0x74, 0x75, 0x62, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x5f, 0x5f, 0x70, 0x69, 0x63, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x73, 0x74, 0x75, 0x62, 0x31, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xf0, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xc6, 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x5f, 0x5f, 0x63, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xf0, 0x00, 0x00, 0x1e, 0x88, 0x00, 0x00, 0xd0, 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x6c, 0x69, 0x74, 0x65, 0x72, 0x61, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x78, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0xef, 0x78, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x65, 0x68, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc8, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0xef, 0xc8, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0xd0, 0x5f, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x54, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x6c, 0x61, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x5f, 0x70, 0x74, 0x72, 0x00, 0x5f, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x54, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0xf2, 0x54, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x6e, 0x6c, 0x5f, 0x73, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x5f, 0x70, 0x74, 0x72, 0x00, 0x5f, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x94, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0xf3, 0x94, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x64, 0x79, 0x6c, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0xf4, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x62, 0x73, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x2c, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x40, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 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, 0x38, 0x5f, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x45, 0x44, 0x49, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xb3, 0xd0, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0c, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x64, 0x79, 0x6c, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x18, 0x42, 0x3a, 0x3b, 0x7c, 0x00, 0x47, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x6c, 0x69, 0x62, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x42, 0x2e, 0x64, 0x79, 0x6c, 0x69, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x09, 0x3f, 0x00, 0x01, 0x73, 0x48, 0x00, 0x00, 0x40, 0x88, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x7a, 0x00, 0x00, 0x08, 0x7a, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x08, 0xe9, 0x00, 0x00, 0x00, 0x56, 0x00, 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, 0x70, 0x4c, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x6e, 0xf4, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x1e, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t MACHO_X86_OBJECT_FILE[] = { 0xce, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x89, 0xe5, 0x83, 0xec, 0x0c, 0x8b, 0x45, 0x08, 0x89, 0x45, 0xfc, 0xc7, 0x45, 0xf4, 0x01, 0x00, 0x00, 0x00, 0xc7, 0x45, 0xf8, 0x01, 0x00, 0x00, 0x00, 0x8b, 0x45, 0xf8, 0x3b, 0x45, 0xfc, 0x0f, 0x8f, 0x1a, 0x00, 0x00, 0x00, 0x8b, 0x45, 0xf4, 0x0f, 0xaf, 0x45, 0xf8, 0x89, 0x45, 0xf4, 0x8b, 0x45, 0xf8, 0x05, 0x01, 0x00, 0x00, 0x00, 0x89, 0x45, 0xf8, 0xe9, 0xda, 0xff, 0xff, 0xff, 0x8b, 0x45, 0xf4, 0x83, 0xc4, 0x0c, 0x5d, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x5a, 0x39, 0x66, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x00 }; uint8_t MACHO_X86_64_DYLIB_FILE[] = { 0xcf, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xe8, 0x02, 0x00, 0x00, 0x85, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 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, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65, 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x0f, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x75, 0x6e, 0x77, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x0f, 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, 0x5f, 0x5f, 0x65, 0x68, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x4c, 0x49, 0x4e, 0x4b, 0x45, 0x44, 0x49, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x78, 0x38, 0x36, 0x5f, 0x36, 0x34, 0x2e, 0x64, 0x79, 0x6c, 0x69, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x58, 0x10, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 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, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x8c, 0x90, 0x46, 0x12, 0x62, 0x53, 0x3f, 0xa1, 0xb8, 0xd2, 0xd5, 0x82, 0x98, 0x48, 0xa8, 0xfc, 0x24, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0a, 0x00, 0x00, 0x0a, 0x0a, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x04, 0x00, 0x00, 0x01, 0x00, 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x6c, 0x69, 0x62, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x42, 0x2e, 0x64, 0x79, 0x6c, 0x69, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x18, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t DEX_FILE[] = { 0x64, 0x65, 0x78, 0x0A, 0x30, 0x33, 0x35, 0x00, 0x2F, 0x60, 0x9C, 0x3F, 0x1B, 0x04, 0xEF, 0x0F, 0x8C, 0xF7, 0x2C, 0x57, 0xB0, 0xF3, 0x2C, 0xE7, 0xF1, 0xBB, 0xDA, 0xEF, 0x12, 0x00, 0x07, 0x82, 0x90, 0x02, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xCC, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x52, 0x01, 0x00, 0x00, 0x5A, 0x01, 0x00, 0x00, 0x5D, 0x01, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0xAC, 0x01, 0x00, 0x00, 0xAF, 0x01, 0x00, 0x00, 0xBE, 0x01, 0x00, 0x00, 0xD4, 0x01, 0x00, 0x00, 0xDA, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xE5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x08, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x18, 0x00, 0x31, 0x4B, 0x31, 0x35, 0xC2, 0x4D, 0x44, 0x64, 0x68, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xE1, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x70, 0x10, 0x02, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x08, 0x3C, 0x63, 0x6C, 0x69, 0x6E, 0x69, 0x74, 0x3E, 0x00, 0x06, 0x3C, 0x69, 0x6E, 0x69, 0x74, 0x3E, 0x00, 0x01, 0x4A, 0x00, 0x25, 0x4C, 0x63, 0x6F, 0x6D, 0x2F, 0x61, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64, 0x2F, 0x74, 0x6F, 0x6F, 0x6C, 0x73, 0x2F, 0x69, 0x72, 0x2F, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2F, 0x41, 0x70, 0x70, 0x49, 0x6E, 0x66, 0x6F, 0x3B, 0x00, 0x12, 0x4C, 0x6A, 0x61, 0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67, 0x2F, 0x4F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x3B, 0x00, 0x12, 0x4C, 0x6A, 0x61, 0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67, 0x2F, 0x53, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x3B, 0x00, 0x01, 0x56, 0x00, 0x0D, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x49, 0x64, 0x00, 0x14, 0x63, 0x6F, 0x6D, 0x2E, 0x67, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x2E, 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x79, 0x61, 0x72, 0x61, 0x00, 0x04, 0x74, 0x68, 0x69, 0x73, 0x00, 0x05, 0x74, 0x6F, 0x6B, 0x65, 0x6E, 0x00, 0x01, 0x00, 0x07, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x09, 0x01, 0x09, 0x00, 0x88, 0x80, 0x04, 0x84, 0x02, 0x01, 0x81, 0x80, 0x04, 0xB0, 0x02, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xCC, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xE4, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xE1, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xE5, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00 }; uint8_t ISSUE_1006[] = { 0x20, 0xF7, 0x63, 0x00, 0x6D, 0x00, 0x64, 0x00, 0x2E, 0x00, 0x65, 0x00, 0x78, 0x00, 0x65, 0x00, 0x20, 0x00 }; yara-4.5.3/tests/convention-portable-modifiers000077500000000000000000000012511501365277300215260ustar00rootroot00000000000000#!/bin/sh # pseudo code: # - find all .[ch] files in libyara/ # - grep for non-portable modifiers set -e find . -type f | egrep "\.[ch]$" | xargs egrep --line-number "\%\'{0,1}l[dux]" | perl -lane ' printf qq[- convention: non-portable modifier: %s\n], $_; $single_quote = chr(0x27); s~\%$single_quote{0,1}l([dux])~\%" PRI${1}64 "~g; printf qq[- convention: portable modifier: %s\n], $_; $violation_count ++; sub END { if ($violation_count > 0) { printf qq[- convention: non-portable modifier: %u instances found above; please fix\n], $violation_count; exit(1); } printf qq[- convention: non-portable modifier: none found\n]; }' exit 0 yara-4.5.3/tests/data/000077500000000000000000000000001501365277300145435ustar00rootroot00000000000000yara-4.5.3/tests/data/05cd06e6a202e12be22a02700ed6f1604e803ca8867277d852e8971efded0650000066400000000000000000000655701501365277300251260ustar00rootroot00000000000000MZ@ !L!This program cannot be run in DOS mode. $J7ZV4V4V4uJ8 V4Wu'V4ǍJ: V4aI> V4aI0 V4V5V48p0 V4P2V48p?V4v0V4RichV4PEL/:R! PP_ pё`u lsplPxlx UPX0UPX1P B@.rsrcp F@3.07UPX!   ` V>D?h)1 Static?oBUTTONURLEDITSTATIC AKSETUP-C8FE-48b4-BC-0D79C7762 0%ld,+wInternal()Applcogon_LanguageID'%4.4![X4Do\sOFTWARE\02/A4APL 113LK*.*TEME?RROR!309etup-{/Si.i_omsctls_progress32>KAPI_<3Ma* ݿY@rXT%Text_ݺa_\stze4 ;Y.dlly3ceGUPrg {rtnÅ(%sykFhBBsC+HGgGdMJ_1A/3{BNCE,NameArrayoF+~Gvn il{auto3lidaXCommd mr3gak.tmp7/B  .A=,e0p3ZyNt01090ƶ/1helr/-Ch-nf#@.O/? %wA|;IAL$) ;>LVAM($--{y>* a{tJ1>bJHx m5({CVv[l@ m4r^ws4ú@ э`P^+hc`@[4&y^n.ȥ\Se=/Ա =n"Mb) F-:28]XV*8ӸbDžb=B:6j@;BXJkͶP.ۚ' v |-t@J|>VQ[Tz?k$%% n`=7]2c cwq Ǝ7e ԔY f{2\SPQ3Di{Gf&4:u%19 HE.7+}ds |Q1n|4vE;} MZ װ K&I;6 $d {;ې9;SR[~D!rvL`RT5hss# ֓KL=DEYYs±Y[3/: D* Kv3i~ {Aslm|=[lxdu(a SO@S>0۔ u$6>S:pBˉtZDU@0ts/~ {F;| 7h1̅e59$t `J<"]9 ?99_ B? p4ƾ%FFRj9k"#:_b|\t .A3 Tj8ݡv9ߕ]Ј?YPPK0E|cSP@2/R9u53M85Æ7YWKֆYtaNXvK8`J8w]›8 f/8mw8oz l^q.d]0jAs,MN6P_N2XD !3VEY3A R!t7lqX*%q,7Vg{M P"gd7t/.YsW9`Ft W0XPQ"7[_A6)W;$f0v݀w!CV6sSU |WXR5(UPtib67/^~r0 ,f0/2w3_έ9fbj@mmfj>}js/a|,=u89]m-3@9Eog^%h?j OY% CX*V/F>n^/؊j} -S@Wcm5_%!#1|,ȱ%-qR p0HE $Z|7pplwɥ`@\w7P*LzD@d.;V ,ş}Sb)*p֜efIPi8P p՘O{EMA&ihj9($hBaoR.! .ߓ+  u#dN>-9hP%Q;}1< @ |$Pe0N§ـY~- , D 9$99/D8NG(ty##ffldNAwS`1A 0lg~ ,ҳN/w_9D# }SPjETMQ~Y>[fY N%Qϭ3#QV z$oAhFu$[;/jف5m1Y9Rwd+NB1uTQu|&$gtnj2BI] ̶E>_9YN^8VD]\uvatmeM`͟ P+Psz?"}s󸜹됀;o j }8^1x^v *F triP`фsn,3W%\^ kp]MN;cwW2uLtfpZHV(h;V)yU%)a\dO`XlKPWnWL9NS_px,iI]W,)Y脇2)a"nqO ^w]BD]NE8t`I&#4L~:"[F̈́R'5Et8P8T5A .(r*y4D (1V ?-[:P%i"3%P F((~'Z?Nr!J'#|";lo4j6u_bYj,RZ`9%c'@' !T;~{%Fj kv0P1[m8-&ZyY3!{W, C@،& '9AG^u^a,V?~Lj#X-`;/2!p\U5йB;uX5jzmXm"&6M& &SA%pQvl Vrd0:688L/,/2j_Y9Y 85r%9*H3^ }ElPt)4o~!R; v46+OpB~9&@B# Y'@2GT' o-ͪv 40{ r^x$0Z][tU`LBDw>u$SnY @< %P)sP"vl 2r,,[ CGmDVjlݾL* 'Eh@4&Z#:YH"93E\Sc-q] E VyGPݳ_"px׊A=v?Vazؿ5Y^5"B_3 [$dTM[? k=~:%VWgp !! ! Afd},(62~bQG;|;vL*@7D{ hCIc+hyAZ+ t{5Eԡ9Z[tn/S^4ES%O4>h>yףlon]X / 1F7g:/mu&-^kc#t`Q xl+2AL`l5"q `!HBBFU0fL65ӣuL3@Y Xĉ)rX*"uw6|;(ʌ }]*#}uޞtJl9Y6$ѯQu4ThtnQ+چSXz;2 ک9 s}Ӏ%,=~HE(Ht%_/WWƘ Wv F ] *9=gTu ַwA$!n܎UMF 57 (ULq!NXklCܾI)X \UL7Md@PR3 KQ&Ou?m u <t .C+Hq4~B~ Y78ǀe!tXxۚ${lj+XjVpyl7'>?7e[xHGqJG_T{T܏3!0>w$8 -4.^]x%\~k#'7ex2Xm WW$K(7C#I8{ d8@,+th rU~\f,g#P$q<}H;u A/l{;](;`xSWI^hYٍC+ĕ[t7*QsRQ8 MR,]^+ dlx0/ ە<0AȻy#{^?~k{sxY Ur!"Z6;YwF{GŠ~! _ HP 2,Dt/ oFP!~w%Yf7fuHnMVҜO"DSEx$bP^ K7N~ǘ n Q. D lovM;2}@ ۗ ~;|KjzD3P7 Vmi΍mlif9; ^ f| 辬 fhDQ( %:뚂(A jh $ěL8  ʐΨ X;87V'$-x;tV; 5h;"^1Bl6+tK\ybLCģ_cԼK,# X%x)SQQ_5b%p#JHuz f,ZJ/ r|0@gg ^f#iy8>j;p 8}\&0~[V)s- ]PT"[%2l9Cm1j 3t`'t4+Un3)hodA.=5vmQ 7 A'^LDvH u;DW>QquP 3C3G 9`" # (91,KLO Vդ(ȷ VwcdRUpR2uo5f҄]ƙ )~ьeC m]u_V$h>iu-fI/hsnEEZ  VǀFrPP&AY ~d?+n^tA#rdZ ta lߊedt&cf)ذ08=2FB;c?t ( W<.hq,En ?F / @M9yB Q6S+z] <1EMESZ8] +>l\tIafNLd&po7ڎE͡y [9/AF@ q@"ݜv*dob pn)J̞;uA_ @DK6p"–p̌fL2b4wgW%O hNE+:)Pzp$-`<u.tea6n fA b>ċpAaJy3`TIA۪d=xNE pmxW; _YNJǮ(lH? ~ oFv|ND LFYH$6 \_ 4eDI^ZXY7ǃk0P=+'3v!pj3& AalE (njjr> $\XU.J UV"`YkAv@%A# nYB rE8v& xј*p#d0VpN@$W YWXÿ @8+YD' X&O δ܁8L6N&}uNfZ:^-;1~ZH# J%#'hGѓv vGİ/ `yKd0LX9݄6Pp|U c2a}Tj:F v _uRF QֺUhv@ jw"QHepWlHX2f jinF@%Cf7ֿq`aYrEJ,) -߉F~;aҞ[qlo(&*,ZJWz0Z~M\`P f|\/`m< >au*X Qj?h3XtY]tWWW%o#X.UR\6g(T%t6\'_etаYXxB=%4/WLkUK+~W ;_|+";}RR| ;VTi0Q&1$NnUroSL>C$|/& <,A4 d B_QCr4>-sdj1vS#ؙ'˶g&q4$ ` F6@84FFFF0,($FFFF FFF S|F>|Б|>>_!|Ԉ<P+&7y> ;PT\`#dhlpt####x|###^8DPd>B%l &P- z aXYďz?6h="˿rlVHCIQ{hL! #-svm U@|xtfЇK~ UmFHh  ^u?LKfz{ w:4/U*=c9&p\^!rq~{T/ ^*q,0Efo /T&u"w꺡 d sM ANJ3jLͭ@7#Fu&AG~4!} a-[73; Hȏ魛bOZRGv<0e&+|h9x۝G0 Cf RlF D鈳CHLu<;3WL ;|k ;Pc/|&PO>ȃ<gt( +f8Ud`3AQ`H"Q *FT?*0GpPֆmhq a΂0wD1Mbvul}{gQueYC{ValEv$Key.|6_Tcki6wVuEv+\ؠxt6a32⡱VHud۱Ykg ST%4۷ 4viCaps_57yQ +ۿlY X m/,L۶ K q&@mٶm#&mۖeJH۶nO*nD_Awm۶"/ih0Ge!߶v,J w Bn۶oAbBmٶ)j5!N&m۶dkҼm ڲmS#\[-˚Z_ c6e۶e bm۶7 9/k 8D?Hju o*_fdivmcRSWamEδfe_d" bncqsplp mbs ͂tiZo{k4. 5Zlm cmo1k'pktf=nb+3bz`LnnM,7 syuܛCxxF=$: $JgeLFtwvHBnrמrld4Z+LomID"EMBNVNc -iV$ $MI`6 g=@SEVk[\og0 ۰C$Ik6pYsf@;زf Bob3flYf4w~XSysC4`mhRZascha nsllc PBkXߺk9bd_e&MAs\yN3ZlcqnToi!{6I@nr%s Na$ab4~UnhoH57H "umChdu Cm`H^pٖ{m$)v\ہ0GL}g%lk 4TrXs,~,c &Lk\ nIP+aOKlo:yG"troyCN랈d,  vN6[  aF3 Tl;S&j ,    ۭ  Gob a"  (' D0<", -_ oo(# #T<9  @{ c-@+ VT $t4 #3 (  Z֏"  ,8 Z׫[a ۷ 1 ~k#]1 HI 5(#;_:M` xm"b뾹< [" l 0k( >|1Bwa'߅e3  ] : bF  Za 1ۿm*5&$0$M R ' G +sW@98j,G%1Q.? &DD7 oL/+|6(!#[^x- &'btfCK 3 _L::%;o9v s ҇9nIN b%t8 I34cV70 HTD&. V.%6  F+9 vi_\+D7=4;]$+,ŭ<3,]=<PEL/:R! 3  {3{d7 @0=P/  r#p pnW0 dvW؄.rdata["uɖ $.Iӽ&'T(ﹸMOsr4`gK|O{X' 𛒀B'7<|$` W FGurusu s1Ƀr Fttuuu Ausu s/vBGIucwL^0 tE_0lcP dGt܉yGPGWHU$d ta1 ^1G t"0<0 +70 0!0 +i[7N 8CIˑ00W~|NYKw;0  *H 01 0 UZA10U Western Cape10U Durbanville10 U Thawte10U Thawte Certification10UThawte Timestamping CA0 121221000000Z 201230235959Z0^1 0 UUS10U Symantec Corporation100.U'Symantec Time Stamping Services CA - G20"0  *H 0 ITK %y"W*oܸ&Csk¿.PZvC%CE{t"״MD$k_E;DCsi+˙r&Mq1QaSI,xE/W?=ƒJ{3y uAQlie)`; tޒ"t|'JÞ-'}aqPK],e ؖ|NHDD h]jxdE`F~T|yq00U_n\t}?L.02+&0$0"+0http://ocsp.thawte.com0U00?U8060420.http://crl.thawte.com/ThawteTimestampingCA.crl0U% 0 +0U0(U!0010UTimeStamp-2048-10  *H  yY0h O]7_R DnmX|0i#s oG9*ÎY M1\*zzWLey@b%n7j!AW?wI*^8j"Q~0085njP0  *H 0^1 0 UUS10U Symantec Corporation100.U'Symantec Time Stamping Services CA - G20 121018000000Z 201229235959Z0b1 0 UUS10U Symantec Corporation1402U+Symantec Time Stamping Services Signer - G40"0  *H 0 c 9D#DIa Sۭ,Jn"hcSit<üu00_:xG\0  *H  0l1 0 UUS10U  DigiCert Inc10U www.digicert.com1+0)U"DigiCert High Assurance EV Root CA0 120418120000Z 270418120000Z0l1 0 UUS10U  DigiCert Inc10U www.digicert.com1+0)U"DigiCert EV Code Signing CA (SHA2)0"0  *H 0 Sdτ5Ѷǣ,,:5:W/HO#~le$U>#|BzbE}ct˞c%EO}u >EzX64+.+1Xf2R>v@Zj=Kv\60L *XA "v^T8bp$pd -⶝!lس{P6 \J9yݿ=: %X0T0U00U0U% 0 +0+s0q0$+0http://ocsp.digicert.com0I+0=http://cacerts.digicert.com/DigiCertHighAssuranceEVRootCA.crt0U00@><:http://crl3.digicert.com/DigiCertHighAssuranceEVRootCA.crl0@><:http://crl4.digicert.com/DigiCertHighAssuranceEVRootCA.crl0U 00 `Hl00:+.http://www.digicert.com/ssl-cps-repository.htm0d+0VRAny use of this Certificate constitutes acceptance of the DigiCert CP/CPS and the Relying Party Agreement which limit liability and are incorporated herein by reference.0U~m2j#pj:k0U#0>iGԘ&cd+0  *H  3J 37ۭ6:.zCBNMݟ !]Cw+ב3lղ;.ɓO@~YVrjAF|If8pwɍ1 )3͉?|mƲ:fk{ئ4XSW`#dM|%d!BC7M&MaKFAeθy ;Ǚ*nm^aƖa-Cbԙjd0P08 D  @0  *H  0l1 0 UUS10U  DigiCert Inc10U www.digicert.com1+0)U"DigiCert EV Code Signing CA (SHA2)0 131210000000Z 170413120000Z010U Private Organization10 +7<DE10 +7<Hamburg10U HRA 11566210U Gerritstraße 1410 U227671 0 UDE10UHamburg10U AKApplications e.K.10UAKApplications e.K.0"0  *H 0 c%5w t '3^'6($B8?|pS|M$@gpLsșQf7 f؈Z^ec 2cĒ8=ߜ1D0@00l1 0 UUS10U  DigiCert Inc10U www.digicert.com1+0)U"DigiCert EV Code Signing CA (SHA2) D  @0 +0 *H  1  +70 +7 10  +70# *H  1o=+d 400* +7 10AKInstaller0  *H ,+,!Ӯ4{Dx o(DȩͧQ덀nI>.eZv5={,E~pG46:2NB4ff)j0VLs1y.Wu\v/v0Z@-s(  Nܙo(;8#A_d6/GoЬʽE9jjZ$Iۈ[v\O_;)@=& #UE 0 *H  100r0^1 0 UUS10U Symantec Corporation100.U'Symantec Time Stamping Services CA - G285njP0 +]0 *H  1  *H 0 *H  1 140214154720Z0# *H  1_d j9XU$s0  *H GO2-gl9O4Vv_B>-ܫ:>:ÌGn`(}JZKE.=l$ t"糧- GsUʍy߈'Dn'곕4bNۛL ~Uadr"x[=={03O|}3C*8qM(K?@G{BAS* E\V5B_Y/"2P#@볬蘾qпyuBVh&j^yara-4.5.3/tests/data/079a472d22290a94ebb212aa8015cdc8dd28a968c6b4d3b88acdd58ce2d3b885000066400000000000000000000406401501365277300255130ustar00rootroot00000000000000MZ@ !L!This program cannot be run in DOS mode. $f" Z"Ce "Ce "Ce 9 !Ce 9 #Ce 9 )Ce M5 !Ce +; Ce "Cd Ce 9 &Ce 9 #Ce 9 #Ce 9 #Ce Rich"Ce PEL[!  -0pA@P62<P*`01@0<2@.text `.rdata0@@.data@@.rsrcP @@.reloc `&@BUM tDftZ66666CUSTPROF.dllCP_DelItemCP_GetItemCP_GetTaxMapCP_PutItem_DllMain@12N@DUeu4 8Ph  P`TZ4VS_VERSION_INFO! ! ?DVarFileInfo$Translation StringFileInfo040904E44 FileVersion27.1.9.33HProductNameQuicken for Windows8 ProductVersion27.1.9.33: CompanyNameQuicken Inc.f!LegalCopyrightCopyright 2018 by Quicken Inc.TBuild DateTue Jun 5 21:07:13 IST 20188 Build Version27.1.9.33TypeQAfFileDescriptionCustomer Profile Interface DLL: InternalNameCUSTPROF.DLLB OriginalFilenameCUSTPROF.DLLPA PAPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDINGXXPADDINGPADDN0`00011#1,1f111,252B2Q2V2a2f2q2v222222222222222 3.3;3@3f3o33333333333344/4G4_4e4x4444444444 5575D5\555$6Q6_6j6p666666677>7C7b7h78 88=8Q8W8888888K9P9g9999999999::::$:4:::@:F:L:R:Y:`:g:n:u:|::::::::::::::::; ;!;(;0;6;<;B;H;N;T;Z;`;f;l;r;x;~;;;F*>N>i>u>}>>>>>>>>A?M?U???????? 00031D111111110 011D1H111124282@00 0$0(0,00 *H 0}1 0 +0h +7Z0X03 +70% <<<Obsolete>>>0!0 +"C-I+M00W~|NYKw;0  *H 01 0 UZA10U Western Cape10U Durbanville10 U Thawte10U Thawte Certification10UThawte Timestamping CA0 121221000000Z 201230235959Z0^1 0 UUS10U Symantec Corporation100.U'Symantec Time Stamping Services CA - G20"0  *H 0 ITK %y"W*oܸ&Csk¿.PZvC%CE{t"״MD$k_E;DCsi+˙r&Mq1QaSI,xE/W?=ƒJ{3y uAQlie)`; tޒ"t|'JÞ-'}aqPK],e ؖ|NHDD h]jxdE`F~T|yq00U_n\t}?L.02+&0$0"+0http://ocsp.thawte.com0U00?U8060420.http://crl.thawte.com/ThawteTimestampingCA.crl0U% 0 +0U0(U!0010UTimeStamp-2048-10  *H  yY0h O]7_R DnmX|0i#s oG9*ÎY M1\*zzWLey@b%n7j!AW?wI*^8j"Q~0085njP0  *H 0^1 0 UUS10U Symantec Corporation100.U'Symantec Time Stamping Services CA - G20 121018000000Z 201229235959Z0b1 0 UUS10U Symantec Corporation1402U+Symantec Time Stamping Services Signer - G40"0  *H 0 c 9D#DIa Sۭ,Jn"hcSit<üu00!C$Vt0  *H  01 0 UUS10U Symantec Corporation10U Symantec Trust Network100.U'Symantec Class 3 SHA256 Code Signing CA0 170412000000Z 190604235959Z0|1 0 UUS10U California10U Menlo Park10U Quicken, Inc.10U Operations10U Quicken, Inc.0"0  *H 0  X6h1"HG,hM.~oJٓߠMM=Ɨ'p@A,B T΃Qjp[돼`i *0=dtWʫ/H;" ;3T^AlG)1uk4S'lsjW x# ҼsP+i#*Stk<](Ƈs%#h,ka*)WyJ#.lGh8hv/>0:0 U00U0U% 0 +0aU Z0X0Vg 0L0#+https://d.symcb.com/cps0%+0 https://d.symcb.com/rpa0U#0;Sy3}.+ʷrf0+U$0"0 http://sv.symcb.com/sv.crl0W+K0I0+0http://sv.symcd.com0&+0http://sv.symcb.com/sv.crt0  *H  (Ad ҙOŔ?@Ze6NR'5AFB=x`n[QKG*; ntb(HyO(.^ qL˜G :_ø,a.vXKDxt\r[>&5 Vh&I\C{!!/{svtAkm^ŶĴt~Dxہ#.P[X`e-9 6`:5U\"%ze00Y0A=xvI`a}ʆ*0  *H  01 0 UUS10U VeriSign, Inc.10U VeriSign Trust Network1:08U 1(c) 2006 VeriSign, Inc. - For authorized use only1E0CU٦V?.)|=꺓P")L:_֤%k/L'{ "`?MLrgw'Ǻ5I(J D 6+P]'KT+^t É"wCL?d!1<08001 0 UUS10U Symantec Corporation10U Symantec Trust Network100.U'Symantec Class 3 SHA256 Code Signing CA!C$Vt0 +p0 +7 100 *H  1  +70 +7 10  +70# *H  1UUr;lE* .20  *H 3W$ԿhQ {!XT,pQ;c%xsqDߨm>$gkuOQӓ=dcS!my,y9$Б |(0 VHZȻM5@NbxF #li!ܳ _a %u/}5q]&(/>>rB*z`QHH@h56T+Oѕ>īLUYuWtpbҚ4aOot$NG 0 *H  100r0^1 0 UUS10U Symantec Corporation100.U'Symantec Time Stamping Services CA - G285njP0 +]0 *H  1  *H 0 *H  1 180605163551Z0# *H  1Lem>N0  *H E 0G$H[W5YUwa3;HG{V8['j O6cQnHPH )I 9)YDg#>m6z8/BlXSn W 3 ݐ) &AxxU`LMN

v8|ެTCFM9k_(4t  o]T\u A+Ĉ1G2P'ߏ&j&!lonT3\1>U0 ;29nkD;tu.7ܥ ;tW;v-XZ  N 'u$_ fWP/R5SjuCavO4!ht.,(Px%mFVvMPQ909áM=LS'3V-9t݋Ț +@I^x@L0;J4n7ƍ=SW 1=HىMS VDS4VN-^kxJ~܉UFk)Mm} }$u̫ -luDsPQhWmLmP`8U+^*d2¥½ ̍4z6_ Ъ|H ]URQȅhG8+׾|MQs"kuxA W.x 2!-h~ظW$K>&~ftBK'jPpyNѨ 6-A$ uu~9^$t-t(G<uc78%;AØZj71GKK^~PwCk<aVEGhs|EQ/ mA@|UIB +J;u nrw!:BFy]`۷(J O un9Wt,w9h}A9QڗP },ۉ/!rQɄ8Y )Sv]p].VrمC}9G O;ώ[=}?t_Ky'_q=AВzsiA:iυ5+NJAJm&]˃S}b[ENڏ'G}qӅ3 I_3 LHFU"4*64Ͳi 54MӠp\B]4M,?l5:?4[zi`VN@6ie3și^QDB.dllcM&E0'JP\HE0AH[RSDSEt 70JK\RoD:\workspace\2018_R9elBld\target\checkouustp'{rof\ease.pdby\9"eu ';avlۯ0<@|2nW 425tf`_ig"y53UȨA rn ޙD%Ueu*i4+U JFQU%Tɨw@T SleepLoadLibraryA GetL .astErrorFr"|PcAddss8cal!= All IsDebuggoerP'enti9UnhandqdExcutionFiltecsmpCuBwsdTmina$Sy`oemTimeAs;e =IdTh߂1ckCouEncod^MXoeIukgiRai$Tmpl-5  :<\.    ! &    (!  S-H-   m=!gG M#  )Kߺ ^ 6/Wmq- $O+ 9Q 9k @3T@] WL[-!  )u -0F@l I9pevoɄA@4@qP6[<Pu`Ew =81ml/<2.`%xt1`.rdºv'_@.&MS'OsrcvhOl Ŧl&'Bbq2@|$`pW FGurusu s1Ƀr Fttuuu Ausu s/vBGIucwL^9G,<w?u_f)ٍ` t<_0ąPGt܉WHU ta1 ^1G t" PA%B2P`KERNEL32.DLLMSVCR100.dllGetProcAddressLoadLibraryAVirtualProtectfree[–l>ZϖږCUSTPROF.dllCP_DelItemCP_GetItemCP_GetTaxMapCP_PutItem_DllMain@12 02 2 02 20 *H 0}1 0 +0h +7Z0X03 +70% <<<Obsolete>>>0!0 +"C-I+M00W~|NYKw;0  *H 01 0 UZA10U Western Cape10U Durbanville10 U Thawte10U Thawte Certification10UThawte Timestamping CA0 121221000000Z 201230235959Z0^1 0 UUS10U Symantec Corporation100.U'Symantec Time Stamping Services CA - G20"0  *H 0 ITK %y"W*oܸ&Csk¿.PZvC%CE{t"״MD$k_E;DCsi+˙r&Mq1QaSI,xE/W?=ƒJ{3y uAQlie)`; tޒ"t|'JÞ-'}aqPK],e ؖ|NHDD h]jxdE`F~T|yq00U_n\t}?L.02+&0$0"+0http://ocsp.thawte.com0U00?U8060420.http://crl.thawte.com/ThawteTimestampingCA.crl0U% 0 +0U0(U!0010UTimeStamp-2048-10  *H  yY0h O]7_R DnmX|0i#s oG9*ÎY M1\*zzWLey@b%n7j!AW?wI*^8j"Q~0085njP0  *H 0^1 0 UUS10U Symantec Corporation100.U'Symantec Time Stamping Services CA - G20 121018000000Z 201229235959Z0b1 0 UUS10U Symantec Corporation1402U+Symantec Time Stamping Services Signer - G40"0  *H 0 c 9D#DIa Sۭ,Jn"hcSit<üu00!C$Vt0  *H  01 0 UUS10U Symantec Corporation10U Symantec Trust Network100.U'Symantec Class 3 SHA256 Code Signing CA0 170412000000Z 190604235959Z0|1 0 UUS10U California10U Menlo Park10U Quicken, Inc.10U Operations10U Quicken, Inc.0"0  *H 0  X6h1"HG,hM.~oJٓߠMM=Ɨ'p@A,B T΃Qjp[돼`i *0=dtWʫ/H;" ;3T^AlG)1uk4S'lsjW x# ҼsP+i#*Stk<](Ƈs%#h,ka*)WyJ#.lGh8hv/>0:0 U00U0U% 0 +0aU Z0X0Vg 0L0#+https://d.symcb.com/cps0%+0 https://d.symcb.com/rpa0U#0;Sy3}.+ʷrf0+U$0"0 http://sv.symcb.com/sv.crl0W+K0I0+0http://sv.symcd.com0&+0http://sv.symcb.com/sv.crt0  *H  (Ad ҙOŔ?@Ze6NR'5AFB=x`n[QKG*; ntb(HyO(.^ qL˜G :_ø,a.vXKDxt\r[>&5 Vh&I\C{!!/{svtAkm^ŶĴt~Dxہ#.P[X`e-9 6`:5U\"%ze00Y0A=xvI`a}ʆ*0  *H  01 0 UUS10U VeriSign, Inc.10U VeriSign Trust Network1:08U 1(c) 2006 VeriSign, Inc. - For authorized use only1E0CU٦V?.)|=꺓P")L:_֤%k/L'{ "`?MLrgw'Ǻ5I(J D 6+P]'KT+^t É"wCL?d!1<08001 0 UUS10U Symantec Corporation10U Symantec Trust Network100.U'Symantec Class 3 SHA256 Code Signing CA!C$Vt0 +p0 +7 100 *H  1  +70 +7 10  +70# *H  1UUr;lE* .20  *H 3W$ԿhQ {!XT,pQ;c%xsqDߨm>$gkuOQӓ=dcS!my,y9$Б |(0 VHZȻM5@NbxF #li!ܳ _a %u/}5q]&(/>>rB*z`QHH@h56T+Oѕ>īLUYuWtpbҚ4aOot$NG 0 *H  100r0^1 0 UUS10U Symantec Corporation100.U'Symantec Time Stamping Services CA - G285njP0 +]0 *H  1  *H 0 *H  1 180605163551Z0# *H  1Lem>N0  *H E 0G$H[W5YUwa3;HG{V8['j O6cQnHPH )I 9)YDg#>m6z8/BlXSn W 3 ݐ) &AxxU`LMN

mscorlibSystem.ReflectionAssemblyTitleAttribute.ctorAssemblyDescriptionAttributeAssemblyCompanyAttributeAssemblyProductAttributeAssemblyCopyrightAttributeAssemblyTrademarkAttributehpjsoaputility.Sv.resources.dllhpjsoaputility.Sv.resourcespthpjsoaputility.XmlStreamSoapExtension.pt.resources 9d7fC|o~z\V4r712|AwX $$RSA1-mb몂&(a=++]FN ´*K$&6!yso{LF m9 a5zh^`}Yz'\Q%`r^1AXO+ŀ0%N% @%_CorDllMainmscoree.dll% @0HX@4VS_VERSION_INFO00?DVarFileInfo$Translation$StringFileInfo000004b0,FileDescription @FileVersion1.0.4400.37258` InternalNamehpjsoaputility.Sv.resources.dll(LegalCopyright h OriginalFilenamehpjsoaputility.Sv.resources.dllDProductVersion1.0.4400.37258HAssembly Version1.0.4400.37258 `5yara-4.5.3/tests/data/33fc70f99be6d2833ae48852d611c8048d0c053ed0b2c626db4dbe902832a08b000066400000000000000000004143041501365277300252630ustar00rootroot00000000000000MZ@ !L!This program cannot be run in DOS mode. $PEL|N 2DP `@ -YPK?z  H.text0 2 `.sdata`6@.rsrc?@8@@.reloc x@BPH8zD 08& ( :&}8.  E1 P8& 8( 8} 8(( ( 9& 8*0;8& 8t! 8( 9 8(  (( 9+ :&*( : 8( t$o l 8r(  9`& ((  8& 8?8( 8'*( t$o l8~  E#-W/iN}0H {r> ( :`&((( 8B(  (( 9 ( :&((<" 88@ (  8((( 8* 8( : 8{ 8t! 9~& *{@ "( :_8Z8( 8@( t$o :g 8!(((( ( 9& 8( t$o 9 !8((( 8{@2 :&( :p 9&*((? 8l8 ( 8T EE :2&*( t$o 9V ( : 8( t$o : 8*(  ( :& e**>8&}*:8&{*>8&}*:8&{*:8&([*F8& ( *&8&*&8&*F8& o *F8& o *Z8& ( *F8& o *F8& o *V8& o *F8& o *V8& o *J8& ( *N8&((*:8&([*F8& ( *&8&*&8&*038&{  ( t |(+ @*038&{  (" t |(+ @*08&(-9n& (-:)&(# 8(+8  E ! 2 8(,8 & 9&($ 8*~8&(% 9 {& (' *>8&(( *08& (.9K&{(/(2> 8*{)  o* o+ 8P  E S0}QFq1 y& nB% 8q{ (3} 8V{ (3;o 9:&{{)  o* o, (8 8 {(/(2> 88{ (/(0u 8& (-:&{) :o* o, 88>X 8{{)  o* o, (8 (-:V&{{)  o* o- (9 :)&{?{(/(2?8(5{(s. (6 8 (.:& 8{(7 (-:&{{)  o* o- (9 8v{(7 8`{?{(/(2?8(5{{) +:o* o- (9 8{{)  o* o- (9 8{(s. (4 8 o/ (19 8{)  o* o+  (-:s&{ 0 s. (4 (.9L&{ (5 85{{)  o* o- (9 8  8 8{ (/(2? 8{ 0 s. (6 8{{)  o* o- (9 8*08& 8!{) :o* o1 o2 8{)  o* {(:o3 8{)  o* {(:o3 8{)  o* {(:o3 8i{)  o* {(;o2 (-:9&{)  o* {(3o3 8  E Z*6} 8{)  o* {(;o2 8{) +:o* {(:o3 (.(-9n& (.9G&{)  o* {(:o3 9&{)  o* {(:o3 8& 8{)  o* {(3o3 8*:8&{ *&8&*:8&{*>8&}*:8&{*>8&}*:8&(4 *08&(-(.:v& 8E{)  o* o, 8#{(=@y8.  E&F8!& 8{(< 8{{(>(8 8*8&{9 {o5 *08& 8S{{ (3;j(.(-9P& 8#{ {(58*  E!8 & 8(? 8*08& 8i{908<& 8N9(.(-9& 8.(6 8{(@8  Evv 8*08& 8 { $((F : &{ X((F 8 {(G 8 {  ((E 8v {  ((E ,8V { (I{(J 86 {(T I8  J((X a(-: &{ ((F 8 s7 }  9 &{ ((E 8 { d s8 (Q 8 { s8 (Q /8k { (G 8U { &((F 86 s7 } 8! {(I{ (J 1(-: &(As9 38 s: } (.: 8 { (I{(J %9 &(Y `8 {([ o8y s; }  :c &s< } 8M s< } .88 { s8 (Q \(.: 8 s< }  L9&{d s8 (Q ^8{ ((E 8{(G +8{  ((E C8{ (I{(J {8b(] 8Q{(G (.96&{  ((F J(.:8 {(P ?8{ ((E b8{ (I{(J F8{  ((E 8{ (I{(J(.:~& 8j{(P :S&{(G 9;&{(V 8${ ((E '9&{ l((E !8{ ((F -8s= } z8(U 8{ D((E G8}s7 } 9g&{ d((E :E&{ (I{ (J :#&{ s8 (Q |:&{  ((E D(-:&{ (I{(J r8{(9 ~8{ p((E (-:~&{  ((F 8^{ ((F 8?{ (((E (.:8{ (K v8(W{(J m8{ ((E 9&{ D((E 8{ ((E T8s7 } 88m{ ((F 8N{ (I{(J =8.{ (I{(J R8{ (B 48{P s8 (Q :8{ ((E x8{ ((F y8{ ((E d8|{(I{(J *8\{ ((E 8<(C S(-:'&s> } 8{ (\ 98{ (I{(J 9&{(G ;8{ H((E t8s? }  l:&{ (I{(J (.:h8c{ s8 (Q 58B{ ((F O8#{ (M 8  <((E8I& 29&s@ } 8{ (I{(J (-:&{(M 9&{  ((F p8x{ ([ 8b{(\ [8M{(B N97&{  ((F <8{ ([ K8{ &s. (H 78s= } 8{ (I{(J (8s= } f8{(I{(J g:u&{)s. (H A8Ss= } 8>{(G V8({ (I{ (J8k  EZ)%VREdh>[m$d5?='yLx/- }@.-;VN,wa!U ? zC+Y WAgcNV@+m -v0gBnUjbv9 ]8Y{(M "8C{ d((F k8$s. (Z i8{ <((E M:&{(D s8s< } 8{ (S >8{(L &8{ F((F )8p{(G :Y&{ ((F E:8&{ ((E q9&{ t((E 08{ ,((F (.:8{  ((F :&{ T((F (-:&s? } 8q{ (L u8[{ (R h8E{ ((E 8%{(G c:&{ (I{(J 8{  ((F #8{(D @8{(M U8s< }  8{'s. (H }(-:g&{(9 w8P(W{(J :4&s< } W8s= } 8 { (I{(J 8{(I{ (J 8{ ((F Q8{ J((F 8{(L 8u(W{ (J n8Z{  l((E B99&s> }  8#s< } $8{ ((F 9&{ ((F H8{ (B 8s@ } :&{(G e8s> } Z(-:r&{(K 8[{ s8 (Q Y(-:5&{ (I{(J (.:8 { \((F 8{ (N(O X8{(I{ (J :&{ ((F j8s= } 8{{(L 6(.9`&s> } _8J{ (I{(J 8**:8&([*&8&*&8&*F8& oA *V8& oB *Z8& ( *F8& oC *F8& oD *V8& oE *V8& oF *V8& oG *V8& oH *V8& oI *V8& oJ *F8& oK *F8& oL *V8& oM *F8& oN *F8& oO *V8& (P *F8& oQ *J8& (R *F8& oS *F8& (S *V8& oT *f8&  oU *V8& oV *V8& oW *V8& oX *F8& oY *V8& oZ *V8& o[ *V8& o\ *V8& o] *:8&(^ *V8& o_ *V8& o` *V8& oa *V8& ob *V8& oc *V8& (d *V8& (e *V8& (f *F8& (Y *V8& (V *V8& (g *V8& (h *V8& oi *F8& oj *V8& (i *N8&(i(j*08&(k(l: & 8\~!(m9y8& 8<! 8,rp(nok sl 8  E (l9&~!*68&~"*:8&"*8&(_ d(~"(o*8&(_ (~"(o*8&(_ (~"(o*8&(_ (~"(o*8&(_ (~"(o*8&(_ (~"(o*8&(_ F(~"(o*:8&([*F8& ( *&8&*&8&*Z8& (m *J8& (R *f8&  on *08&(}(~:d& 8(|84  E / 8(z 8({8& 8*08& 8)(s 8(z8X  E&7M \ 8(|(}9!& 8 p(( 8v& (}:&({ 8*08&(}9z& 8M( (~:984{+( 8{+(8*  E8& 8*08& 8{+(8*  E!K8 & 8( :&{+(((}(~:& 8*V8&(&{#*>8&}#*>8&}#*>8&}#*>8&}#*08& 8{$(8.  E'H^8 & 8( (}:&{$9(}9& 89 (~9&*08& 9J&{' (( 38*{%(( (}: &{'es8 ( /8{+ Ts8 ( 78 n(( *:&{(( 9&{& (( 9w&({%( =:Z&{)( 8C{* H(( 8$s7 }' 8{&({'( 8s7 }* B8{&( >8( 8{(( #8s7 }( 8{) >(( 58k{'( 88U{% (( G86{)Es8 ( ?8{*( D8{'xs. ( !8( H:&{* V(( '8{& (s8 ( 8{*( $8y( %8h{( (( 8I{&({(( ,8){(ws. (85  EIOo@g MaoO. 'OO&8"z;HVl7!(~?#e-d^@ 8{+so ( 8s7 }) ;8({+( 48( 8p{*Es8 ( (~9M&{) .(( 8-{*h so ( (:&{+( 8{*vs. ( 8sp }& 08( 6(}:& ~s8 (8& E8{&({*( <8h{+ ^(( &9H&{(es8 ( 28){' (( .8 {%Uso ( 98{+( 8{' ( so ( -8{%( F8{'( 9&sp }% 8s{&( 8]{(  so ( :;&{)us. ( 8s@ }+ C8( 8({&( 8{) so ( 8( )8"@"PAsq ( ":&{&( 8r{)( (~9W&( @8E (( A(}:&&{( (( +8{&({)((}(~:N& 8{% s8 ( 19&{&Vso ( 8*:8&([*F8& (r *&8&*&8&*Z8& (s *V8& ot *V8& ou *:8&(v *:8&(w *F8& (x *F8& oQ *V8& (y *F8& oS *F8& (S *:8&(z *V8& o_ *V8& o{ *V8& oV *V8& o| *V8& o} *F8& oY *V8& oZ *V8& oI *V8& oW *V8& oX *V8& o~ *V8& ( *V8& (e *V8& ( *V8& ( *F8& (Y *V8& ( *V8& ( *V8& ( *V8& (V *V8& oi *V8& (i *F8& (j *08& !8{4s o (:!& 8(s }=8& 8( 8{8s o 8a +j}> "9J&~ {7s }8 8)s}6 8{8% s s }5 8{ o 8{4s o 8s }< 9&( 8( 8~{i(( 8d{4s o 8Cs }? 8.( 8s}48 ! E$W@=B4 "pUMav%( (9\&s }; 8F{Q{6( #8+{8s o 8 s }: 8( 8s }7 8{ {5o 8{=s o 8{8s o 8s( 8c(( 8Nr?p}@ 98&{=s o 8{ {4o 8( 8*08& 8~ o 9~ (o {7o ݺ ~ o 9a~    (o (  ( (o*  0 (((o D ~ o 9/~ 6 (o* N (((o ~ o 98F  E Ng=08& 8~ ((((o 8( 8y~ o 9 8`~ o 9 8G{ { o o :&&~ (o 8~ (o ((9"& 9&~ T (o 8{ ~ (o 9&*3Dvv3Dw08&((:& 8U~ o 9. (97&~ (o 8(8f  E 4M 8~ (o 8& (:&~ o 9 8*0 8& 8~ o 98q& 8{Q((?s(9& 8~ (o 8X 9& 8r~  (o 8T8w{Q(((  o* X ( (o+ (8  E dM=wY 8{6(  o* o- :8o{6(  o* o+ o 8g~ o 9 9M&*0 8& :&(  o* {6oo3 9&{79l 9u&~ o 9 8[~ 2 (o (98&~ o 9 (:8} 8& :&{ o 8(  o* (o3 8X (9& (:&{7o 8 8y8L(  o* X ( ({Q(((o3 8({Q((?8  E x*T6$HZ;x 8(  o* {6o;8o3 8g( 8U~ X (o 87*08& (:5&{L(  o* o (8  E-F Yj % 8{Ls. ( 9&~ o 9 8}( :k&}A 8Y~ ~ (o 8;{Ls. (8& 8}A 8{4( o &((:& 8~ o 9* 8~ (o 9&*0\ 8& 8( (o o 9&~ o 9 8( (:k&o (:T8O~ o 9z 86~ (o 8s 8  E !h]h s<CU#! 8~ o 9 8h (o (:I&( ((& 8.~  (o (:R& 9&~ \ (o 8*( 8{5~ o 8.& 8~ (o 8o 8~ o 9 8j{8(  o* o s { o ( 8#8X( ((& 9&{?o 9 8{?o : (:&( 8{5o 8o 8{5o 9x&*0R 8& (9&~ o 9 8o :&{?o :m :&{5o 8( ((& 8~ o 9 8f( (o o 8@o 8/( (:&s 8   Es\%$Q\jE K =Wh  8{5~ o 8g~ o 9 8N*(8)& 95&o 8#~ (o (9& 8~ & (o 8~  (o 9&8( ((& 8{?o 9 8{8(  o* o s { o ( 8:~ o 9 8!~ J (o 8 (o 8{5o (:&( 8*0  8& 8M( 8<#?CH :!& ( 8  (( (; 88 ( (( (( (9&{;o j[l 8  8z( j[l 8_#?C 8F ( :2&#@[ 8~ (o 8  ( 8(s (:T& 8(  o* o,  8  8~ o 9- 8p8 l ( r (( z (( 86 ( 8#  ( (:&  ( 8 R ( X (( ` (( 8#@[ 8#@[ (:& ( (( (( 8P  8A#@[ 8)({;o <8  E v.J5bRn?E: +X[#8& 8k ( 8X**0 8& :&( ((& 8~ (o 8~ o 9 (:c8^{@s ({9(  o* o+ o { o > 8 !8{?o 9 8{?o : (:&( ((& 8~ (o "8~ o 9% 8{~ h(o 8]{?o 9 %8B 86( &8%8{;o : 88{?o : 8~ o 9 (9&( ((& 8~ o 9> 8{@(9 #8z: (:e8` (:O8J 8>{@(9 8${;o {<o X{9(  o* o+ o { o ? $(:&(((& 8~ (o 8~ &(o 8w~ o 9 8^~ 8(o 8@8( ((& 8!~ o 98Z  E'Y-d)yK=>:Wr ;! 8U (:D&{?o :*8@& 8"{?o : (9& 8{?o 9 8*0X 8& 8o 9&{;o o ((9/ 8{;o o 9 88(  o* o- o ((9& 8Qo 8@o (:*&{;o o 9 $:&~ h(o 8~ o 9 8(: (:&{;o o ((9 8(  o* o, (:(  o* o, 8(o (  o* o+ o 8o 8[  E&"uX  S@u3z#\:eGJ :X&s #(9B&o 80{;o o 9 8{;o o ((: 8{;o o ((9 8{;o 8(  o* o- o 8so 8b{;o @ 8G8T(  o* o- o 8o 8 (  o* o- o (:&o 8(  o* o- 9 !8o 8(  o* o- o 8& 8i(  o* o- 9} 8C{;o o 9 8#(  o* o- 9 8s 8(  o* o, o %:& (o :&*08&(9& :&s (9k&~ o 9 (:L8G{@o 81o 8 (  o* o, (:(  o* o, 8(o (  o* o+ o 8o 8& 8 o 9& D(o 8n(  o* o- o 8H~ (o 8*o 8o 8  EU#x 7QwU? 8*0 8& 8~ o 9{ 8 (o 8o 8o~ b(o 8Qo 8& 8:o 8)s 8o 8>  E O~5~`(:& (9&*08& (9F&~ ((o 8!8 B(( & (:&~ ((o :&((((9& 8{7o (9 (:&*(  o* o2 8h (( 8M \ ( (::& 8#((:8  E;V* ^;a0 8~ (o :z&8Q (%X ( ( (:G8B(  o* o, 8 ( (9 &~ o 98& :&{7o 8~ o 9 8 ( 9& 8{7o ( : 9t&*0Z8& 8"{5~ o 8  E2L59|Tp u@3"(5t8l&US#WqY )8)~ o 9 -8{5o 8( (:8*{?o 9 8~ p(o +8( 9&(9c 8{{?o 9((9U& 8P{5o (:681~ (o ((:&{5~ o ,8 .( #8~ <(o 8~ (o 8( 18~ (o .8q{5o 8[~ o 9 (:=&{5~ o 8"( 8(8d& 8~ o 9q 0:&~ o 9R /8( 8{5o 8{8(  o* o (s { o ( 8V( 8D(: 8/{5o 8*{?o 9. !8{@r?p(9 8{5o &(9& '(:8*( "8 4( 8( 9m&*~ o 9 %8R{8(  o* o (s { o ( (:&~ o 9. 8~ (o (:8{@r?p( 9 *8( 8( 8{@r?p( 9 9_&(( (@ (:681{8(  o* o ((s { o ( $(:&*08& (:>&~ H(o (:&(8  ES55br (9&~ o 9(9=& 8~ (o 8~ o 987& 8i*08& 8I(  o* {L( o3 8(8`  E iEY* E :&~ (o 8~ o 9Y :&~ (o 80& 8n~ o 9((9& 8E*08& 8V{O(  8@( :o* r?po (:&{O(  8{O( 8X 8& 8( :o* {O(o2 9&s }O((9& 8( 8p8{O(( 8N{O(i? 81 :$&{O(@8  EKe{;m& (:&{O( 8*0 8& (9#&{j(b(8`  E'@Uo WpA 8{j(8& :&{j( ( 8v{g( 8`{g( :I&( (:3&{P(@ (:&{P(( 8( :o* {P(o2 8{P( :o* r?po ( 8((:& (:x&{i( 8b{g( (:H&{i( :0&*0;8& 92&{d(" 8( 8   E&$b- 2CV5n5wPH :^Y 8Y(}@ 8C{;o 8.(((:& !8 {[(# :&( (!& 8(@ (:& (( $8( :o* ~ o (9z&(8& 8c{@( 8K{@(( 8.( +:o* o3 %9&#o*  8( (!& 8(  (:&( (!& 8(l 9&( #8}{\(# 8g{@s :P&s 8?( (:*&{Q($ 8( 9&{Q((( 8{G(" 8( :o* o2 9&( (:&(  o* o3 8h{F(" :Q& 6(( 86{](# 8 {a(# "8 *08&((9& (:*& f(r?ps 84  E"." @ 8{:(% :&r?p( 8& 9&*08& (:6&(( 8*{:('&8*  E:8& 8{:(&:((9& 8*8&{:(&9{:((to *r?p*08&((:!& 8f8.{:('&8:& 8E (:4&{:(&Y? 8X 8  Ey 8*0A8&()9(9& 8"8P(9E8  E &H&zY` 8{Q(*& (:&{;{;o o 8( 8~(8& (:b8]{;{;o o (:6&& ~ (+o (c((&*A&w0)8&(:|& 8o 984  E&2& B 8o o (:&o o 8& 88!o ((:W& 8.(,: 8(8&  E8& 8 9(-* 08& 8(8*  E6Z8 & 8{]{;o (# 8(((9& :&*08&(:& :&{6{6o;8o8{6(.o 8c{Q(/ 8N(.{6o@8& (:#8{6o8  E9| 8*08& 8s: 8c{Q(2(3(5{:(&s 9/&*{Q(2(3(49Z8p  E9=iy+ D4S 8{Q(2(3(6(7(89 8n*(r?p(9D((9F& 8>{Q(2(3(4: 88{G("85& 8{: (% (:8{Q(2(3(5 x((9 8{G(" 8*o 8|( 8j{F(" 8T{;{Q(2(3(4t$o o 8( 8 {Q(0(1; 9&r?p( (:&{F(" 8*0V8& 8{M(" 88(8F& 8{Q((;9 8i 8]( 8MX :>&*(9~ (:t  8i?q8Q  E z9/j! ?^O 8(r?p( 9l((9& 8{d(" 8x*08& (:0&*(= 8 (=8*  E;8& 8(9~ (<9(:& 8*08& 9&(8R  EFM( e4{`8 & 8*(> @) 8(r?p(9 (:o&{G(" :W&(>@ 8@{F("(9s& (:&{Q(0(1{Q((;@2 (9&8{G(" (:&*( 8( 8{F(" 8( 8u*(>.@ :\&*0i8& (:&8(At! 8c8(,: (:D&(6(7(B9((9A& 8 8*  E8{& 8uF 9 (-{\(# 8(r?p( 9u (:8{Q(0(?:K 8{Q(2(@ 8& 8{Q(0(19 8l* 8_{a(# 8I{]{Q((;(# 8{\(#8B  E ll@0_ ((9&& (9&{a:{Q(0(18(#*08& 8*{Q(2(3(6(7(B9 8*{Q(2(3(4t$ 8(Co 8{Q(2(3(5o (:& 8:" 8o*o o 8X*s 8G(h((& 8-{@r?p( 9 8*{Q(0(1: 8(G@U8& 8(J (((@(& 8o  %Ё(H(I> (:t&(Fo (9Y&o (: (:9&(Do (:&(Eo 8  E4Oz` 8o(O 8( 8*08& 9M&{G(" 86X 8({Q((;<8<  E9)g/eOe IC0#YqE 9&{[(#(9S& 9`&8L(At! (:o& (49$((9v& (:D8?(,: 8){; (4t$o  &8*  Eu8& 8SuF9(-{Q((K(6(7(B98 8V( 8F{Q(0(? 8*{Q(2(@ 88r?p}@ 8{a(# 8*{@r?p(9 8*{Q(*& 8{Q(0(1: 8(g((& 9m& 8`{F(" (:E8@8i(At! (9& 8 8:  E-B-R (:&8=(,: :&(6(7(B98& 8uF9(-9 9g&{d(" (9K&{Q((;? 8*{Q($8& 8{Q((K(L 8{Q(2(@ 8{Q((K(6(7(89V 8{b(# 8*08& 8{d("8  E gg# EQ%5K 8{Q((M 8{a(# (:o8j 8^( (:I&*{@r?p(9 8({F(" 9&{G(" :&8(At! ((:A& 8 8*  E1F8,& 9&(6(7(B9 8(,:m 8uF 9 (-9 (:(8#{;o (: &{b(#85& 8(g((&((9& 8{Q($ (:&8r?p}@ 8( :{&{[(# 8d*708&((9& 8*(N:i 8r?p}@ (:f&( 9T&( 9B&{Q((;9 8"*(O 8(r?p( 9 8*{@r?p( 9H 8{d("8n& 88e(Q ((:D& 9&(8&  E%8 & 8(R: 8uF 9 (-{M("8  E^Cp.  8(P 8*0o8& :&{@r?p( 9$ 8c(To 8& 8Ho (: 8. (( 8( 8*( 8o  %Ђ(H(I? 8 ((  8(S: 8(J (((@(& 8i(UY(V\;! 8J*{M(" 83o ( 8r?po 8  Ep![fYK@ Qu0:| 8*s 8(Do 8s(Co (9 & 8R(Fo 8=(G@ 8'*08& 88n(At! ((9H& (:&(X8&  E%8 & 8(,: 8uF 9(-{Q((K(4:8_  E e%{{ 8{Q((M 8{Q((K(5 ((9r(9=& 8n*{Q(W 8X{Q((K(X8*& 81{Q((;: 8{Q(Y :&*0u8& 8Y{;o o (( $80{< o o ((8+  E.+1-7`{*JaD:.H Vz )A]M 89{;o o  j@ !8(X 9&{;o ? 8o (]?z 9& X (8( {< o o ((!&((:& 8}o o  o (( 8V{c(# (9;&{;o (\ 9& {<o ?| 8(L 8( {;o o ([  #o* (!& +9&r?p(( 8(X 8{Q( &(( 9\&( {;o o ((!& 8,{Q((Z 8( o o  o ((!& ':&( {;o o l( (!& #9&r?p( 9 (:&8s{Q({< o o ( 8`8u{Q(o o  o ( 9.&(7(^ :&(7(^8& 88 (:&( {< o o ([#o* (!& 8{;o *8( o o  o l( (!& 8a :T&( o o  o ([#o* (!& 8{< o (\ %88{Q({;o o ( &8X )8( {< o o l( (!& 9&o o  (\ 8l: 8[{@r?p(9: 8<X ,9-&(L :& "8 {c(# -8*08& (9&~ n(o 8e~ o 9 8L~ .(o ((:W& 8{ o 86  E r))T>8 & 8~ o 9 8{ o 8*0{8&((:S& 8~ (o 8~ (o 8~ o 9 8~ o 9 :~&( 8l{A9 8W{Ls. ( 95&{L(  o* o (8L  E 3_N 3!t7 8{Ls. (8(& (:&*08& 84~ o 9 :&(  82  E^@}8Y& 9&~ r(o ((9& 8~ (o 8}~ o 9 (9_&*0 8& 8 { }9 :p &{4o"9` :T &{9o { o l#0A[8& 8 {9(a? (8 {9(a: 8X (:88{9o { 9  38~ (o )8{9o { @ #(:j&{4o"(_(` 8J(  o* o = 8#{L(_j{9o { v(((s (i& 88{9o { : /8{4o"9 8{9o { : :|&#@[ +8c(  o* o {9(a?* 82~ o 9. 8{4o"9o 8{Ls. ( 88{L(_{9o { o   {9o {   ( {9o { (   (  ((   ( (s (i& (:!&{4o"9R 18{4o"s. ( &8{4o"(_{9o { o s (i& (9&(d~ P(((e $8u( J((b((c (@((:& 48/8 {4o"9} ,8(  o* o3 %88{9o { @ .(9&( 08{L(_{9o { o {9o {  |({9o { (  ( ((  (( (s (i& "(9&~ (o 68(h 8~ o 9' *8 (g 58 #?C (:r8m(f& :[& 8N{4o"s. ( 8(#@[ '8{Ls. ( 8s 8{L(_{9o { o {9o {  ({9o { (  ( ((  ((s (i& 8.{L(_(` 8{4o"(  o* o ( 9&{L(_j{9o { ((k(s (i& 8{L(  o* o ( !8n8~{L(_{9o { o {9o {  ({9o { (  ( ((  (( (s (i& -:&{9o { o l#0A[ 88{9o { @~ (:T8O{L(_j{9o { ((j(s (i&8#  E74.Ahar4C{ >Lb t q?>5.R* 2(:&#?C& 8*0 !8& <(:8{ 9 N8{  ; 08{4o$9 8~ (o :&{?o 38{ ;S D8{?o _8p8y~ o 9 P:Q&8Y~ o 9$ %82{ : "8{ 98N < Eg  u? mPR2G v"Vipj[TIPr)-Vs;(!l  n v& .> J L#\3;B:`  8U{?o 9>&~ o 9 8${ 9Z @(9 &{?o .8{ ; ]8{8(  o* o (m e8{ 9 K8{ o j[}> 8z( F9g&( '8T~ (|>( (o :%&~ R(o 8:&{<o 9&(d((& 8{?o L8{<o (:& M:&{ @ 8{4o$(" 48i{ 9 b8T8~ o 9 86{ ; C8 { ; 68 (n((& :(:&8{ @ A8~ o 9 -8~ o 9j W8{ 9 *8{ ; B9p&~ f((  o* o ( (o 98-~ (o >8~ &(o V8~ o 9C 8~ o 9- G8~ o 9d `8~ P(o 8~ *(o 58j~ (o 8L{<o 87{?o 8!{?o J8 ~ o 9 8( I(9&~ 6(|>( (o Z8{ ;d &:&~ H(o [8w{ 9{ +8b8k{ ; R8G{?o !81~ (o (8~ 0(o f8{<o #8{?(l 8{8(  o* o (m 8{<o /(9&{<o :n&~ o 9 Y8T{?o T:=&{9(  o* o o :&~ (o 78~ o 9 (:&( ((& )8~ (o 9&{ ; d8{ @ 8i{  ; $(:M&~ (o 19-&{?o O88~ o 9h ,:&{ @ 88~ o 9 S88~ o 9G 8{?o 8& U:&{?o \8o(  ((& 29T&{! 9V ?8>~ o 9 a8%( (:&{4o$(_(` (:&(  ((& ^(:8}C c8{8(  o* o (m E8{  ; H(:m8h{ ; 8R~ o 9W ;89~ (o (9&{?o X8{  ;$ (:8{! 9 Q8{?o 8*0"8&(9x& *8(o:) 8  ( 4(9&8{ o" o# ($ (:&8}{ ;h 88^X 8{ ;< .:x&{  ; 8`{! :$ 8K{  ;s !(:/&{ @ 38{ ; ,8{4o$(_(% (((i& 1(:&{& (:88f{  ; (9&{4o$(_ v(s (i& :W&{  ;~ 8?( ~ o  58"9 8{4o$(" %8 o o  884o" o#  &8{<o 8Q& '8(o? 88H{4o$(_ (s (i& 8Z{ ; 9C&9  (:-&{<o 288e o  9& o 9(:(& 8k8){< o o &8& (:>& (,: 9&&{< o o &8  EtR 8 9 (-~ o 9 88~ o 9v 8~ N(o $8{ ; 8 ( 78{ (9u (:8(  o* {4o$( o3 8]{ ; )8G ( "82(' & 8{ @V8B * E:HR%2=m$no%Nc54] ]iQRQ (:&# 8(o? 6:&X (:&~ (o 98s  8{4o$9A (:t&( ( o2 8V{ o  :<&{ ;& (: 8{ @j 08{ ;. #88 8{4o$( -8r?p 9&lD ((:8 +8{4o$( 8j*$0; #8& ?8{( : ;8{5{) o* o+ 8s, .8(pu F:&{?o : 8(- {5o. s/ o0 ':s&{5{Bo1 8V8{?o : 886{?o :  8(r( %8{5{Bo1 -8{5o2 68{5(qo3 ((:8{4 :( 38~ (o 9z&{4 :3 8d(r( 8N{?o :$ E83{?o 9 ,8}B 28{( 9 :(:88} +8(qd;2 :&~ P(o J8{5(qo2 <88C{5 : 5(:a8\s, (:& "8@8{4 9 !8&(6 ( /88{5 : (:&{?o 9 D8(qd; 8{?o 9 88,{?o :> (:~&{4 :g )8h~ o 9 A8O(7 {5o. s/ o0 8(8{) o8 @8 ? EK4rRaOLp ys(%k5UV]?m47!]!,g6R| H8{?o : 8(9 J({@({5o. s/ o0 >8n{?o 9 G8S{) o: @ *88~ o 9? :&(; {5o. s/ o0 48}B $:&{5 : #8} 8(< ( =8} 0(:&(= ( 8z8={> @1 9^&{5(qo2 B(:=&{5(qo2 8!{) o8 (? {5o. s/ o0 @8(@ D({) oA ({5o. s/ o0 8{5o3 88[(B ( 8}{? o 9 :`&}B 8N{4 : 898{) o: @ 8{) o8 @ 8{> @} 88q{?o :O C8}B 8{5(qo2 19&{( : 9&{5(qo3 8& 8b8%{4 9 8H{( 9 &92&{5 : I8{) o: (C {5o. s/ o0 98*0[8&((9!& 9&~ o 9p8{& 9&~ (o 8{5o 8(D & 8v8( 9_&( 8N~ (o 9/&( +:o* o- 98  E m U}C-% 8~ o 9 :&*0f$8& 8{5 *(oE (9&~ o 9 8q{9(  o* o o { (s (F &(9R& 8){G (t(ut 8&  E'8 & 8{G (H & 8& {5{9(  o* o o { o N({9(  o* o+ o { ( X(( ^((voI 8  E M/Cf' S/{ 8~ o 9(9$& 8~ (o 8& 8~ t(o (:a8\*Pw0%8& 8u{5oJ 8& 8Y{5o. 8 {5o. {5oK 8&~ o 9~ 8 ~ o 9(9& 8{5 (oE :&(8( : 8{5sL oM (:&: 9q&~ . (o 9Q&~ (o 82 (8 ( :8  EoVO Jof=& 88(N : 8*0 &8& (:Z8U~ (o 87: 8'8{8(w9w8q  E#jM4 d 9&(8p& 8*( 8~ o 9 8r}C (9\&{8{ o ( 8:{9sO ( :&s 8~ o 9>((:;& 8~ b (o 8*0 '8& (:88{W(}(| 78a8:{g( 38F{j(x( :(:'8"# 8{f( .!((( 18{W(y(| :&# 48{j{C( 8~ o 9) 8~#@[ &:f&{X{W({j>{W({j8i(~ 8)~ l!(o =8 ~ o 9 (:88{f( !( !(( $!((( 28{f( 8{j( ( 8p# ((9& 8L{Y(P ( (( ((( )8{9:" .8{i{j({j({j(Y{i({i(YY[X{j({j({j(Y{i({i(YY[Xso ( ,8_{Q((;:' '8@{j( 8*8{?o 9 (:&{h(y(z 088{h( (:&{g{Q({Q({Q(Y{g({g(YY[X{Q({Q({Q(Y{g({g(YY[Xso ( -85{@s !8 #@[8  E>yv.:# Tdl<NPdD:\D#! W 8{>lCq 8{?o 9 88( j[l :&{f( ( !(( !((( 59g&{h( /8Q{@r?p( 9 82{h(f l[Zj 98{g( *8{h( :&#?C 8#?C? 8s# 8_{d{Q((;(" "87#@[ $8{Y( <8 8 {h(f T!(#Z  Z!(( b!((( 8{9(  o* o o { o {<o Y{;o Y j[l 8\{?o : 68A8# 8(8N{?o 9= (:8~ (o 88p{9(  o* o o { :s8& +8{;o {<o X j[l #(:p8k#@[ 8U#?Cb ;8;{?o : 8 #A, %8*0%8& 8K~ o 94 (:-8({M(Q ( (: &oR ( 8~ o 9 :&~ !(o (:+& 8{S !(((8`& 8(s9 8l{j( ( 8R{U "((( 8-{T !(((8  EK*al5%eO  (:&{e(( 8{R !((( 8h( 9W&~ <"(o 88*08& 8p~ "(oS 8R~ oT 9E 89{^(# 9"&{i(8N  E\O\qL6m(9& 9&~ \"(oS 8{M(" 8s:N 8c{i( 8N{N(" 97&{i( 9 &~ oT 9(8& 9&{E(" 8*01(8& (:8( :o* ( :o* (o oU 8c{Q((?5 8C(  o* oU 8(  o* ~ oU 8(  o* oU (9&(  o* {7o oU 8(  o* oU 8y(  o* ~ oU (9& (9C&(  o* ~ oU 88 o* X ( ( (:& 8(  o* oU 8(  o* oU (:&(  o* oU (:a&( {Q(((oU 8/(  o* oU 8A  E`/&Lr, :rS*{M 8( ~V (W 8iX 8& 8U~ o 9 8<(  o* oU 9&~ "(o 8(  o* oU 8( +(W 8(  o* oU 8*0G)8& (:^8Y~ "(o (:6& #((s (F &86  E ~QQ8((9}& 8~ #(o 8~ o 9P 8{V({G (t(&~ o 9"8& 8@ 8.*!w0*8& 8O~ <#(o 81(: (:8~ #(o 8~ ^#(o 8~ #(o (:8 :&(s (F & 9u&8<(s (F & (:F8A~ o 9E (:#&r?p(988  E,PznH^^x}Sjl+ (9&{V(( 8s{V(((:'& 8L~ o 9 83 8'r?p(9 8 {G (t(ut ((9F& 9 &{G (H &8"  E8 & 8#&{V((:8 ( (9X&{V((Y*~ o 98Z& 8%~ o 9 (:8():] 8{V((Y*{V((: (:8{V((* *S|#w0)8& 8^ (:G&(s (F & 8"r?p(98  E (ij Q 8~ #(o 8~ o 92((:}& 8v~ o 9 8]~ #(o 9>&(): 8(8(s (F &8& 8(: 8{X *0+8& 8(Y 8^  EQ:kZ9 j :& @$((Z H$(( 9&( :$(( 8a( 8P N$((Z 84([  : &( (9)& (:8~ o 98F& 9&~ $(o (:&(\  9&~ V$(o 8( (:k&~ o 9< 8Q $((*08& :5&{=o] 8k& 8(^ 8  E ccL+ x 89 8}= 8{D9(9n& 8{=9! :q&{D(- 8[*0,8& 83{_s. ( 9&{g( t8{Z( j:&{G %(( o8{f  s8 ( =8{_ 0)(( 8{Q( '8m{I((| :8S{Ms. ( :1&{H({X( g8{d &(( a8{g %(( >8{H($ (:&s7 }G (:8{bs. ( 8u{H( 8_{W( :I&{H({I( 8({N D+(( H(9&{N b+(( T:&{L `*(( 8s< }f (:&{b )(( @8{U '(( [8g{\s. ( 8F{Y((| 8,{Ns. ( 8 {H({G( 38{Q '(( S8{h x%(( (:&{i( r8{Q{Z( b8vs< }Y #9`&s7 }F :I&{Ds_ }Z 8-s` }D E8{g %(( *8 (s9 8( 8{Gs. ( P8sp }J (9&{H({h(((92& 8b{e %(( s8B{E( 8,s7 }E 8{J *(( h(:&sa }T 7(:&{h %(( `8s7 }d 8{S '(( 8{g({i( ]8b{i((s8 ( 8D{Z ((( X8${Es. ( 8{Q( 8 J,(( 8s< }h 8{Qsb ( 8sp }H 8{H L%(( 8g{F( 9P&sc }c 8:{H({L( 8{g ((| Y8{^ )(( )8{E $(( G8{X &(( 8{Y &(( 8s{E $(( ~8T{e &(( w85sa }R 8 {K({M( +8( 8{X((| 9&{ds. ( 99&sc }\ 9&{I((z (:z&{j((| q8_{H({f( (9:&{\ ((( 9&{K( V8{H({g( (: &({H( B8 {J((| 8 {W( : &{N( J8y {f @&(( 8Z {Q($ 08D {g({j( 8$ {[ l((( z8 {H({d( 8 {Dsd }V 8 {Q( 9 &{g( 8 {` p)(( (:w &{a <((( 9U &{[s. ( (9. &se }Q Q8 {M( 8 sc }_ 28 {i((| 8 {Q{V( 8 sc }a 8 {Qsf ( p8 sa }S -8m {^( {_ {` ( 89 s. ( &8 {G( .: &($ c8 {K( ;8 {Qs. ( 8 {Qsg ( W: &({J( M8 sh }i 8k s: }P A8V {c *((8\& K80 {K *(( _(: 8 {`s. ( D8 {Z( d8 {H( u(: &{j +(( (: &sp }g %9z &{M +(( 8Y s. ( 8= {Y &(( 8 {f((| $8 {a T((( 8{I x*(( 8{H({Q( 8{K *(( f8{d( 8o{i +(( <8O{J *(( 9/&{T '(( 8{X( 9&sh }W 8{H b%(( 8{X( 8{I *(( F8{i( 8z{O +(( 9Z&{L( 8C{L( 8-{Fs. ( N: &{Zsi ( v(9&{i ,(( U(:8{V 0*(( !(9&{H({Y( 8tsp }K O8_{F $(( 8@{H({e( :&({K( 8{] ((( 8{Q p'(( y8{W '(( 68sc }b I(:8{L H*(( 8e{H({E( 8E{as. ( ,9#&{i( 8 s< }e l8sc }[ :&{g( 58sc }` e8{i((s8 ( 8sa }U 8{V(( 8hs7 }M 8S{] ((( C92&{b )(( 8{X &(( "8{\ ((( 8{X( 8{Qsg ( (:&{j +(( 8u{_ P)(( ^(:P&sc }] (95&sh }X 8{j((z (:&{H({W( {(:&{h((| 8( (8{Y  s8 ( (:8{Z ((( 88e{F $(( 8E{g Ps8 ( Z:#&{h  s8 ( 8{[ ((( 8{c )(( }8s< }j x8{` )(( 8{W((| (:o&{f &(( \8Ns> }L 89 X,(( 8{R '(( 8s7 }N |8% sj ( m:&{K({N( i(:&{W F'(( :&s. ( 8hs }O 8S{H( 8>{H({F( 8{W(8h  E%ED}{0:y,R?O0 z Ks&| [AY;Be}F|Nh }0SbJ+]ug b;L_gg`m ~)= ,Ra1}7+&,[9 ?o t: mR *f8&  o? *&8&*&8&*:8&([*F8& ( *J8& (R *F8& o@ *08&~A ~A sB jj~A sC *"8&*0108& |8    8  +8(.: rY 8  9Y 8y Y 9W   p ZX ;8-9/  IY 58    X 8 k X 8  8F-9  6Y 8 8 S TX 8k    :J 8,:)    8,: TY 8 K .X 8  68  8  X J8#,9v  i SX *9R    86 b IX `8!    !: X 49    9  *Y V8 {Y h8   tY 8}    8]   7 X A8B x 0X 8)    X ?: 1Y 8   >Y 9  u Y W8  8L* 8    $8,*:k GY 8*9H8D  EY 8): Z ]X [8  5X 8   9    8    4X 8   d GY 8q  E 3X [8J }82 8 ) <8)9    L8    U9   1Y `8    8  8(98 U X D9f JY 8C   NY 8(9 /Y 8  v: L $X \8':,"8   @Y 8   8    :n 8p'8u'8z'8' 8E 8t' 9/ V X 08   8  ,8   HY :8    8   LY ]8 { LX C:v  8b    @8B =Y 9$   1:    98  nX 8&9   8   I8%: 8  R8o8% !8Z8%j8% z8%988  :  9Y 88 NY 8 M pX 8   q8    w8   MY ]8  |X @8^ @Y 8I 0Y %8$:8  k 9Y 8 MY 8   8  8  8 s rX 8  8k    X Q:K , @X 9-   . zX 8   X X8 8j#8;& 8 :    8    8  k jX 8]  wX 8>  =Y M8   BY H8    8i8l" 8 GY '8 KY K86"98    V8x  ?Y 8U   o X 91  |X 8 5 Y a8!:8  28 9Y 8 L /X 8 k UX 08 Z X F9f D tX 8I   9, % X 8    8 cY #: )X 8    ;8 HY : d X 9f 1Y 8I  K81    &8! 8Y : SY S888rp88 8~8 d8    M8   CX 8n . ;X 8M   d81 + X x8   8 | Ee}o2^c^ 4 P8.Gv dd 5+; zGr  .oSN@ho 4*  vrFr_b.F+ r [|ELv  ~e]/ Wwx% > k suS G9]2uZK l}G " kf  BM T| XFC[!`I ;g[-VV7Dr: zp66 Y,"  N !&-tKR S ? _W gK Z gc5HIb+{J > y\) A -+   ??>< I8U8/ 8+:89    8    g8  :  V (X 38   (:  ,8   68  SX 8e  o !Y P84:^88   z cX 8   8 <Y 8 X )8 FY X9  CY -: 8Y \8x  78` X 8G -Y 8":! H 'X 8  1 -X .8  mX 8 DY 8  8   2 vX +8n X 8Q:F   a8*   X 8 +X 58 ;Y r89   9   .Y 8 2Y 8{88i8 8:N lY 89 KY _8  Y *8 X 8 8 5Y F: FY 8    :v    H8:U 98   b8$ W X 8 o pX 8 LY 8    Q8i>s 89   ~9~   |X :Z    :=    8)  8  8   hX f8$:68  GX 9 FY G: j =X t8e X s8L   { zX o85 BY Z8   8  GX S8    8    8: l Y A8:8  oX 8j O X 9L 2Y Y:.  sX n8 @Y .8 4 tX :   3 (X E8  89   G X e:v    %8Z  X 8E  =9$   X ^8 8 DY 8   % <X 8   B8    8    l8e  8 8O   g JY c88  5 kX :   8 7Y 8c:8   /Y u9 6Y >8  T8z .Y W898S    R8:8-    8   SY E9    b8 BY 8b9    88H 8D: =Y 8b @ X P8::    8& 1 [X 8   8~i:- 8 yY L9  c8 DY : 2Y :_    8K  9Y 8 :8    y8 98  O8 :j8    8    8 9    tX /8z8f 8j 2X {9H   O vX :$   8  @X "8  N GX p8    8 L /Y :  HY 88 4 +X 8^    8F   " yX (8'   j X Z8   HY D9 8  8 [ X 8 _X C8 9 T X i8 98g  J8K ? X 82   MY 8 SX :8  Y Y #8    8  j8 W PX :   28 98a  /8E  kX 8(  YX N8    8    8    :  : X Y8:v8 @Y O89r8n   FY >898A <Y 8,   >Y 48   U /Y 8   DY 8    T8 <8   : SX &8  @Y 8a U 3X k8H 7Y _8/   8  G8  OY 78    rX 8   38   GY 8:U8    8c9* 8R  kY =8:8% LY U8   QY 8 AY 8   o Y B8 :8 $X '8 Y 8y   8Y    8:87  b Y 9   + UX ?8    9   a uX $: SY 8    98z  8c    UX8:g& N8< <Y : ' bX 19 \X 88P "8 j iX 8  8   >Y 8z  HY 8[ -8K ?Y )8* < wX m8 UX 8    8^98~X 8888(38(28 &r?p**(48(58B(58(484(48K(58(/8(48(48(48sD 8(58(48t(58(58((!8ok 8((8|()8wsE 8(58(58(-8<(#8C($8@(48D(58T(.8(,8(48(58_(!8rok 8m("8msF 8h(18u(*8(58(58(48(48(58(#8n(&8i('8e(48k(48Z(58(58(48(58(58sG 8(58(48(58#(58(08(48(48(58(48 (58<(58p(%8(+8(58Y(48q(48m(58/(48L(48o(58'(58w(58(58Q(58@(/8(58*$.>b.0)18&rpoH &(I (J ioK *"8&* 08&(L &* 0.8&tRoM ( 9tRoM &tRo2 oN o* r pr?poO ( 9*tRo2 oN o* r pr?poO n&o rpoP oQ o* ( 9'o rpoP oQ o* &r?p**(+28]W0_28&sR  oS i 8oT X Y= 9oQ *?P 0k38&sE (U  %П( oV %Р( oW oX sG ioY oZ o[ *0 48&*0 48&*0;58&r-p o > * *0;58&rap o > * *0;58&rp o > * *0;58&rp o > * *0;58&rp o > * *0;58&r1p o > * *0;58&rep o > * *0;58&rp o > * *:8&( *J8& (R *V8& o4 *F8& o\ *V8& o] *J8& (L *F8& oS *V8& o^ *F8& o2 *F8& o_ *V8& o` *f8&  oa *v8&   oY *F8& ob *F8& o[ *F8& oZ *F8& oc *Z8& (d *:8&(J *v8&   oK *&8&*&8&*N8&(7(8*:8&([*F8& (e *N8&([( *&8&*&8&*0S8&(?ok (@(A(B ,((C ,((D9 (E8*068&(F(G   %С(H sf (F(G(IsE (J(K(L(MsG i(N(O(P(B*N8&(Q(R*J8& (R *F8& o2 *F8& o_ *J8& (g *Z8& (=*Z8& ( *:8&(<*:8&(J *V8& oh *Z8& ( *V8& oi *:8&(U *V8& oV *V8& oW *F8& oj *v8&   oY *F8& oZ *F8& o[ *:8&([*F8& ( *&8&*:8&(]*F8& ( *0&78&(b(c `sk (d*z8&~: s^&*0r88&{: sl }{(e(f(a(g:(hsf (i(e(f(a(j ,((k(l(m (nok (o 9m sF (pj(q (rԍi(s&(t(u{(v(f(a(w&&r?pr?p (e(f(a{(g9{(gtR & *(g>w'Bi0)8&(f ,(x ? (y *F8& ( *:8&(m *V8& on *F8& oo *F8& oH *V8& op *J8& (L *:8&(J *V8& oh *V8& oi *J8& (g *Z8& (s *J8& (R *V8& o4 *F8& o\ *V8& o] *F8& oS *v8&   oq *F8& oc *J8& (r *F8& os *f8&  ot *V8& ou *f8&  ov *J8&(_(*68&(|*:8&(_*BSJB v2.0.50727lF#~F|_#Stringst#GUlDu#USE#BlopF #GUIDfD#BlobW= $|,}*8  (FlqF5PkK#2KFc 3Cw|9Q1|u|| o   O ^ |  | | | | |4 |R | |# 4 @    "L Q o |  &s|$|||\{7||&F|%|H|V| |& &&,||&(| C**!7 Hn *S|x|||||"|* .$ / oM a "| Q " Q . / 2  $! e!u!"!Q F"|""*\*D#R#"i#"~#"#"$$$$$$$%%%7&Z& & & '"'*'x'|'|'|'|' ' 'CG(X(w(X((().=)/ )%)()* *$****+",+Q =+O+"+Q 0,%i,%.,/ *,&W-\- v- "-Q #.. . .8/|F/ P/|e/|}/|/ /|&'000w11|6v222|.2/  3$|3|3|4$Y5|7$J78$i99:|:|<.??@ .\/ @ACCD E|G|PH|ZH|H|H|0I|K KC&KK$!L|".LQ LrOQOOP,PkP]QjQQQQ QQQ$QQ R$RQ'RQNRWRRQS{S$S$S$S$SQSQTQUcVQgVQtWQRX{XXXX ^F^^^^ _ [&_H_Z_i_[]]]'a\]!^le#pi,m1ik q{]~ ]~0uf]q] ]yCV]i}6]9]<ySyW q[i[ ][ 3]^F]zqzqzqzqzqz]zakE h r           * H [ e o y            E h r      CVKVOVXV[QcQm_Qw_,=Xc_'2=Hbm4?JU`kvCVJ V K VK VK V&K V/K V5K VBK VOK V[K VdK VrK V~K VK VK Va_Vk_VM_N O O a       (() z*M- .s +    :-8*(     (   ( akTCaM WZ[[/[C[W[P f)!&H%"AX%7Wh%F[x%Pb%Zh%ml%q%q%u%u%&u&6 ,&S D& uX& p& &f)& h& l& q&2 q& 'a T'fT(aZ ( 30( ) - ) /  /  /  /  / /* 0kZ 0MZ 0WZ 1hZ 1r |2) \Gh lGq xGq Gu G' G: GM G` G H H 8H PH8 hHT Hs Hu H H  Hu H% IIl Ih% (Il @7:>lT7X>lh7r>|7>7>7>]7>u7>l7?7%?  8J? 8j?u08?H8?\8?E p8?E 8?8@ 82@ 8U@l8i@8@ 8@ 9@u 9@49 A D9,AX9OAX l9nAu9AW9A9A 9AW9B]9B9(B]:G$>G<>GT>Gl>H>rH>H>H>H>Hu ?I $?JI]Xl(f(a(QQ#*Q6,f-a -QQC-QM-YXh-f)-gXl-f)-Xh-a^-k-Xl-X -Y-,+Yu-@?Yu-TSY-lgY -{Y -Y-Y-Yu-ԈY-Y%-Y-Zu-,Z-D/ZC -XCZ-xWZl-kZu-Zu-Z.-ЉZ-Z-h-Oh-(k[h-1111  11z1   z?"["-- z1OAQHQOQOQxQAQQ     f)!f31fAAf3If3Qf3Yf3af3if3qfyf3f3f3ff3f)f!CGN!Sf) z ~)  1I W1f 9~)A , 'Q < ' )fT S b f 3) }2 ~; B g f  Z ~  9) arif)fff)f)f)f)yf)qf)f)y  f  I WWyAy,K3gS~3)~81r)%)i853ABq;IAqByPYLWoetAyg>)f*B ff)f f))e3 h5WrW&)FAy5-PD fff f iF )qff*u 3y8 f)f ?$f)f),f Xf)f)f!d4f=!tQ!d a!Sa!3!)a!S!C)2 ~a!3y!~y!3!!_ "a"S%"92 ~]"ym")")1""""""f)"3 #)#_%#36#f#$##)##$2  -$C;$ f3R$a$o$f3<f $$C$ $WD+ /%1!B%~X%#g%3v%A%8Df)%D%"%Kf)%3"3f)&3%Kg%3v%AX%&A"3"#%<&~9d&&&"{!f)A& &)IfI&~ & & '! L8'!F'~!V'3Tl'!'~ &y'_'3(3 (~f)(3"(30(3 <(|9(Cdf )Y")1)L)[)_lfh)v)C))))~tf *_*(*f)$+B*O*f*|f *W*Z2 ~*b+le!=+w++f)++ f+++A+A+u!+,,?,P,},,,,9,,-~-9$-AD-g- Q}- I- Q- $ -A -) f$ H A-O Yf] ..@.I.~aj.3ap.Si.q._y. I._/W92 /W%/Wr)rIf f)1f)fQf)9f )f)ffAf)ff/ / A0 )A0 0 0~ 1~) ) )k1 f  11AI W1 12W22, i!4 )< 3 03C[32V )3d 334C74DI W)4i )4~)4, 4d 2o )#5d5A5!553 6v ,6~a66)6363!7{ )  !u7~) 7A1 ,8;8 I Wh8z8z14d 8S8~8Si9W)<9))U9 9I W)9 Af *: YL:WY#5 q: I: )I WI:q ; *; 9f A8' l'zY ;;;u7a=< )g< <)f <)8' q) ->)N>))l>)1> > I W e l>)<I W9?^?~?? 53!S?E ?E J '@F@$l>)i}@A@I W@z@WAHAAcA] AAziASAYAW2WYPBW1ABWBWBWBW Ck B 1K3PCnC)Cx 9C  DS DI WUD DD D)YE E FYBFWAdFFWAE F F )F)#G )JG)G )G G G  H/H   F H 3q I 9;I 9^IeIWYIWBJ zJJJ) f K K KfKL3" \LhL L L )u7~[M M)M N f)1O O$ I P3 Q7PWI]P: PI 9PU .Q[ Q f)f)f)f)f f )8R~A=R cR B R R~)R~)R{R SfE4CSSSiSoSoSuS{M)S2TTTT)TTSS!QS#R%cS'oS``(`H`X`x```~C|M Q /  2[[[<[?\3)\7mP\;w\?\Co\GE \K ]O :]Sw a]W ]{ ] ]R]{]/^=sc^  !"#,IVCIFreeDiscBurnerBooleanSystemmscorlibRuntimeCompatibilityAttributeSystem.Runtime.CompilerServices.ctorVoidAssemblyConfigurationAttributeSystem.ReflectionStringCompilationRelaxationsAttributeInt32AssemblyTitleAttributeAssemblyDescriptionAttributeAssemblyCompanyAttributeAssemblyProductAttributeAssemblyCopyrightAttributeAssemblyTrademarkAttributeComVisibleAttributeSystem.Runtime.InteropServicesGuidAttributeAssemblyFileVersionAttributeNeutralResourcesLanguageAttributeSystem.ResourcesDebuggableAttributeSystem.DiagnosticsDebuggingModesAssemblyKeyNameAttributeSuppressIldasmAttributeAssemblyDelaySignAttribute8ab3e03f-a509-40c0-9748-b1698fff3facFreeDiscBurner.exeYRNhRr4j0FsknLt8rAvQqh27CJiMMYP8w5r9ObjectListViewColumnSorterJe86RK63fBXcmwNbQY3LXCLJYmdP5uWYqeXEOptionsFormOptionsFormBaseDVDVideoSoft.DialogFormsStringResourcesFormDialogFormSystem.Windows.FormsMyDialogResultsEnumMainDvsMainDVDVideoSoft.AppFxPNqRWwVLB4923jmRX2fvValueType0klGdRlII0sVI4oEckxNEV7H1rDuOHOBXbDJResourcesFreeDiscBurner.PropertiesSettingsApplicationSettingsBaseSystem.Configuration{CB9AA69F-4951-49D2-98A1-18984DCFDB91}__StaticArrayInitTypeSize=20{9EF7AF60-4C56-4FC7-8D08-014E7C2D5F69}r0FRMCtP7ewaoFygJ7jnCU9aFHZh5wmf6bI2SFU4mbT3GMret7THonfMulticastDelegateYvktN9NN8wd4pmsbLQG84xgbu3UR2KgWPRUYiLGkmDLVFCGQJCe6WdAttributev1YGZ6ZXPZ7Gm9rymS`1s1k5XWVUBkaO14OfgSFVS5B4xjiXrO6pJHQ8Ers8VfR0d6iPR1Wl9D0Cs3EeciDxRacdXaXJAFj5lmPAsiLphbQJ9V3dxLlsMageREUkUVgyq3JBw1Sj3pY14lMegSBHXd3FHml9sKs0D8D6P7GTHrTTHwTnE7eNq8{7F08E812-B9AC-421D-B143-19E5206A834E}__StaticArrayInitTypeSize=32__StaticArrayInitTypeSize=16__StaticArrayInitTypeSize=64__StaticArrayInitTypeSize=18__StaticArrayInitTypeSize=15{CED6773F-B4E3-429F-B0A7-214930634C6D}X7OogKkbGTZd4FFQMPSortOrderComparexyListViewItemDoubleDateTimeIMediaItemDVDVideoSoft.DiscBurnerApi.MediaItemDVDVideoSoft.DiscBurnerApiget_SizeOnDiscInt64CompareToget_IsDirectoryset_SortColumnvalueget_SortColumnset_Orderget_OrderqX1OBWlMIpeYV4QdGN62UKcR0yx2PCvqAuvXL4IwfnZmlC9OiFuYUJR9IVNRkArErpiRxV6QerCYFQIr4n3qmOZVLpget_TagxpyJCrpSudRFvlBi89get_TextIp8E1mMKvWwcUCdVhfop_EqualityKuXkoLGwF9AWjZwVFsget_SubItemsListViewSubItemCollection2Z24t4xaZ1jIOaWAXUget_Count9l1SXMfGWyOq6Cjtutget_ItemListViewSubItemRH5GvRPWOUBqNjSMr7Iy5aTehgyRVUCqSZXLXEZCCwBNo5eoewOpWNConvertToDateTimeSortColumnOrderIComparerSystem.Collectionsn4jowRXs3NTnhKl4Pkym9Jofck0P4s6o1VO4360PDYyIUbemLZ0C8LoTEvMUepEq7ejWH5S5Pwnl6Kb6REventHandler`1EventArgs0qK14WRxbNnQyImYFnIContainerSystem.ComponentModel2u2DYlnsXButton8VUNYJEBLtppu4noGFTabPage1wmvf8Wgdyg7eHaMVCComboBoxmshapGUpILabelMDfAGRNcsHqiVY794MTabControlBQTgr16MEMJjF355Lh6JW6TH5iaFolderBrowserDialogX4XThrMZ6CheckBoxVuVi1iLFYAUJ30i4vJqknjX8bBGLLQphKNbPVHqcfh6D6TextBoxupWIBCNyo8DKSZgQFZ7xyfoBVjjQjAUIqof5F61Q9XYPDeqQhNbNSToltGocgXWqlCxUssB1IQFrCtRNHR7fdRHVESadd_DriveOptionsComboSelectedIndexChangedDelegateCombineInterlockedSystem.ThreadingCompareExchangeremove_DriveOptionsComboSelectedIndexChangedRemoveparentInitget_CenterToParentFormWindowUtilsDVDVideoSoft.UtilsCenterToParentSetCulturecultureDoSetControlValuesComboBoxItem`1PropsProviderproviderToStringGetIntGetStringDefsDVDVideoSoft.AppFxApiGetBoolEventHandlerIntPtrget_ValuelanguageCombo_SelectedIndexChangedRememberControlValuesGetCultureFromComboSetGetLanguageComboGetThemeComboget_DriveComboset_DriveComboget_SpeedComboset_SpeedComboOnCheckUpdatesClickwUHCsRWOigHu8Xi095InvokeTUYYjgtvVDisposedisposingpyoHM6Vc6ComponentResourceManagerSizeSystem.DrawingTyperJWKbXYjgZsoerlhLY5NoGtag1WqSYO8vfAtoHtvekUKNLLoGQJGHAasv2x3VdOYDQY4u29Nget_ItemsObjectCollectionI4CCo2aUPvlnDeaqvOOIQs8pwkHXC4ebNEl24KoeoOjqeJ4vnCK1fZXPeMByuJFqLNIW7WPgListControlget_SelectedIndexNXGAN55eW4lQir0844remove_SelectedIndexChanged7WGado26eyKk2qqHCHset_SelectedIndexuN9HJyANExIqI5fyssadd_SelectedIndexChangedN2tPsbL19pP3B3EwYYControlset_EnabledHMYE3nbBaRIhLd3eKhset_TextZebax03LcXWu4hfwd2set_CheckedQjUmpdQNaH4NXA1u8bget_CheckeduBkcIB7J52kAfC52TWrNCTmJiEFUyrA3gMf1set_SelectedPathmm529bJDqc8pMARGfEDialogResultCommonDialogShowDialogb5QtAfNm5YlYtZJ1M1get_SelectedPathQbiihgDNnSUHMc5VN6set_DialogResultNNQdkOn1yIhkrTBfXFIDisposableJ02UIfSBQbgsyLaG9tRuntimeTypeHandleGetTypeFromHandleBWof3SOS9M2h9uFmdNSuspendLayoutSrIiEKrXEdnkQxnLlwIRIHlXd2Ofbuf0ecDprxGFHbWuqyD2pYvFwbApplyResourcesilLqsEKjeFkc0iFinjset_NametNPFFp6v1L6m6OR2k1ButtonBaseset_UseVisualStyleBackColorliW6S79WcCUhuY0YVtadd_ClickUMOFBw1Z0y8bjgAok0get_ControlsControlCollectionadL0iSvoKr43eOVSJiAdde0TwdSspHDorZuhETsLYFKLBEqBDlFKAJ74qComboBoxStyleset_DropDownStyleq5QcorFShuKMckuPKLset_FormattingEnabledThcIN5Hd5hRAOYreGnColorget_TransparentvIrRXEq4rlrFF2V7EFset_BackColorbdIjwxTeAsl9gwDEgpCheckStateset_CheckStateAN1CfT8VVOZjPcTs6gset_MaximumSizexKrXcmtxhreM4aXhN4set_HotTrackOx6PdjzgBkSXjeJOc7CJVjJ4omW3CBpms5pPaset_AcceptButtonIButtonControlgDD1rIooueCEm2A5pmHAutoScaleModeContainerControlset_AutoScaleModem4TkyLo4LpFeOogEdNkset_CancelButtonPRJnFdoC7sSckqnDI9xYbhmowoRIcOYElkbcuauwHAQwoZ8heMRHmQLscset_ShowInTaskbarkRsgPBokojZ6VoKBN2Kadd_Loadg0YdiwolnhQ1ilS7yFmResumeLayoutMn6eZto0dxUYEbGxgjUPerformLayoutLwu9EuoItRUM7WjG2g5DriveOptionsComboSelectedIndexChangedDriveComboSpeedComboresourceManResourceManagerresourceCultureCultureInfoSystem.Globalizationget_ResourceManagerget_AssemblyAssemblyget_Cultureset_Cultureget_AddingFolderget_CannotAddThisFolderget_EraseBeforeBurningget_EraseBeforeBurninIsoget_ExceedingSizeget_FileCanNotBeDeletedget_FileCanNotBeRenamedOIw2L7oGZpiRe0JwMgvTiWmjvoxIZ7B64vbhM2kY3It7opjW4TTU5WAkyE8X6ZHoM8tci5yyUu55n10OXpof7v7a5FbPEYKReferenceEqualsZMUjyLoPTJpfQVMJWbFrHyLlwohx4vhnJmrUN1CultureAddingFolderCannotAddThisFolderEraseBeforeBurningEraseBeforeBurninIsoExceedingSizeFileCanNotBeDeletedFileCanNotBeRenamedPanelfilenameAddProcessStringstrcolorShowMyDialogPointSizeFSinglePRXE54oelyfijNIXPSsIwrqhgoXPcb4l9jBBnWtnXiY9oB2LOAcnu0Tu3pI7kwMoypMT8rMHYaOh0Hm2eBoc0NYJpaPJoXSConcatgyF7cRoge22HhvdOpsdset_ForeColorQQrID7oUMSjN3fjDkVcTextBoxBaseAppendTextDhUX2DoYjHtaJowHjgWApplicationDoEventsg2tAsfoVHL5sgfyuspISystemColorsget_WindowTextIjUOVsoacrn0ZuwYIKAHsUX9Wow0AfP3Udau3FyT6Z8lojwX6RXTnBWDARDADbgoucnatjj4HIg2HGWoKDo5gxFU3KWajWLA0CJqko2niqRgkjaMV7get_ControlDarkKatGRCoAflVbpDuGjI4UpCL1poLcgNXdupk5GEset_LocationLO1yejobcGh1Y10AgIIKxw8Hwo3EBbwRT87esVset_SizeNsJ6dToQc61ZbCs5PhYset_TabIndexhRcmoSo7TQrtM1WSjX5WPlDLwoiZX1Vq61ZaLR5iL2XroJYRiTPOcU4bDluxvDEoN4tVO09svggEG7eeLWoDxX7Hb634R2A1jDLnkonncx6EuYc1FNset_Multilines8t9R4oSUeucq0Ye91nset_AutoScaleDimensionsKj3UwgoOWxTg10rEXRcXXueQhorqT544ByCw9Pset_ClientSizelEcYALodNrTe9nd8NWbset_ControlBoxAtAtX3oWJ6r4RIry5INFvUJP6oKXHJnkIaPGhjFormBorderStyleset_FormBorderStyleT78nnbo6opTrR2fEThmset_MaximizeBoxCex1E1o9WiMgGBZDsXAset_MinimizeBoxM2TywRo1BfffDSbJD1UZsRhwwovoEhNAPWUjXaon5BO6osnrKdEGDpnQsd2pgE0oE5l9ZZUXCbxHvalue__YesYesToAllNoNoToAlltFXEdQtmWG2L2f8iHkgogKgkAoJ9gywSkQvi6Tyzf1mnEFormProgress4R5omsWoTkYdQoonq5Q8IBurnerManagerjKRo4IS17PBurnWorkerDVDVideoSoft.BurnUtilsB6GoC03RbvList`1System.Collections.GenericBurnerInfoI2Uo876IruStackW8loYSqLyYMediaFileLayouthfHoHs7UHUcfool8A8jxDeviceVolumeMonitorPVJo1mqho5AYuoyI7iMlBurnActionh9poD2uXbcFLFoN76uad9iSou98Y7ygsZovtHpjacYHoehUCgBQUYoalMgOvUfBoABrEqtnU4oVwo6aM8wLogEPiidAafoFWfPmyMPqo60XAkrXdSoTQagGgbFjoiVveLJeM9o3BpvZqFJCojVTAKuBOOopuNHi3OpenFileDialogOZ4ocuWH4X034oIl8goGListView8xfoScDXeEColumnHeaderUfLofrCsU0sbtoU1t6CcPq1oQptD4VsQNohIadMWImageListyUOoGeSeQ8PictureBoxlfGox4L4bDiXnorm9vePp9qoddvDhNContextMenuStripDBeo571Xo6ToolStripMenuItemYEwonMJxbi8UNoW0C0I06aloPKPjRCthVo9GN0y2FsDoqMuGUqBlnoB9kcuhkWFoJixkXu2LmoZPsDVqycVos8ObJNI3WokuRub4tKwobna1vulKOoRrO8lDH5EoOcHHY224LoMi7kCGeqwoL5k7QJadd_CheckUpdatesClickedBurnEventArgsadd_DeviceListChangedILogWriterLogDiscWorkerDVDVideoSoft.DiscUtilsCancelStopProgressHandlerLocalizationManagerlocMgrILocalizableVoidStringDelegateadd_CultureChangedTaskCompleteEventArgsadd_CompletedBurnManagerDVDVideoSoft.ImapiDiscBurnerDeviceVolumeActionadd_OnVolumeInsertedProgressChangedEventArgsadd_ProgressChangedadd_OnVolumeRemovedBurnerExceptionExceptionget_IsInfoEnabledInfoStartget_IsErrorEnabledget_SystemErrorErrorget_CurrentCultureApplyCultureForAllIPropManpropmanApp_Title_PNset_Itemget_IsTraceEnabledGetProviderOnFormClosingsenderFormClosingEventArgseshowOfferScreenWriteCurrentCultureStopGetShowModalInputParamsToEraseDVDVideoSoft.DiscBurnerApi.InputParamsset_EjectMediaset_RepairUnrecognizedRwMediaset_ClientNameget_PleaseInsertDiscEmptyShowProgressFormset_FullEraseBurnerTaskDefInputParamsToBurnFilesInputParamsToBurnIsoInputParamsToBurnTrackAtOnceInputParamsToBurnDiscAtOnceget_DiscIsNotEraseableContainsHideAndClearset_ExclusiveAccessEnableBtnCloseDriveInfoSystem.IOget_RequiredSpaceGetSizeOnDiscget_NotEnoughFreeSpaceget_ClearPlaceget_FreeSpaceget_NotSpaceOnDiscFileInfoDiscSizeInfoDVDVideoSoft.DiscBurnerApi.DiscPropertiesDiscSizeget_TotalSizeget_InsertDVDDiscGetRootItemCountBurnFileSystemTypeDVDVideoSoft.DiscBurnerApi.DefsGetRootItemByIndexget_NameDefinedByUserset_CloseMediaset_VolumeNameset_DiscWriteSpeedset_FileSystemTypesset_MediaItemsset_ContinueMultiSessionset_VerificationLevelBurnVerificationTypeset_TempDirectoryForStashFilesset_FilePathset_MaxWaitToFinishSecondsCharGetTempDirectoryForStashFilesFileUtilsCreateDirectoryWithAlternateget_DiscWillBeCleanedget_DiscContainsDataFunctionsConvertBytesToStringWithSpaceDelAllMyFolderItemget_dataAddFileSearchAnyItemAddDirectoryIEnumerator`1IList`1IEnumerable`1GetEnumeratorget_DisplayNameset_NameDefinedByUserget_CurrentColumnClickEventArgsget_PathDragEventArgsDataFormatsFileDropKeyPressEventArgsCancelEventArgsIEnumeratorFormPresetNameset_BtnOkset_EdNameget_EdNameset_LblNameset_BtnCancelset_CaptionDelAnyItemStringCollectionSystem.Collections.SpecializedStringEnumeratorGetOutputFolderPersonaldgE5aw5DDcfFn6aBKNITagProviderDVDVideoSoft.DiscBurnerApi.UtilsSmaWm8JAYOR1Px3LnhF0b9H96WkCheckForUpdatesyysq1JPNCProcessBurnerInfoListIsDiscValidDiscResolutiondiscResolutionDeviceLetterIsBurnerValidget_FreeSizeBurnMediaPhysicalTypeInsertedDiscRecorderTypeCommonUtilsMediaPhysicalTypeToStringIDeviceInfoDeviceInfoget_FriendlyNameProgramsCompanyRootUrlget_NoRecordersget_ProbablyBads6sBGnGxDCanWriteDiscget_DiscIsNotWriteableIsInsertedDiscBlankaneJil6ktDiscWriteSpeedInfoget_WriteSpeedAllDiscSpecDVDVideoSoft.DiscBurnerApi.DiscSpecGetDriveRecordingSpeedUInt32MediaWriteSpeedsTryParse78XZA2mflBurnerTaskEventArgsProcessingStringBurningFilesStateDVDVideoSoft.DiscBurnerApi.BurningStateget_ApproximatePercentSetProgressget_BurningTracksGetColorProgressColorKindAddProcessStringsSetTotalProgressCancelledget_ErasingErrorget_BurningDVDFolderget_CurrentActionTypeBurnActionTypeget_ImageBurningget_CurrentSubActionTypeBurnWriteActionTypeget_ErasingInProgressget_BurningErrorget_BurningSuccessActionTypeTaskKindMessagesTraslationsBurnActionTypeMTget_BurningFilesget_CurrentFileget_ErasingSuccessBurnWriteActionTypeMTY5asir4WTShutdownWqCkB0lMIIconSHFILEINFOSetCaptionBaseWinApiSHGetFileInfohIconDestroyIconCompleteProgressFormsuccessmessageset_DisplayModeProgressDisplayModeRemoveLastProcessStringPlayFinishSoundFinishSoundN36b8XNiH9khRSi6HMget_OccupiedSpaceget_BurnGetAppTitleWithVersiondLeON2LoiDebugget_IsDebugEnabled5MWMQCsbeIPropsSaveToHelperAddStorableValueLocaleUtilsDefaultLocaleNameExtensionMethodsKOdLRq8NboqM745Bq43AWXAbKRXszTypeNamerls0AD6Zfget_Monthget_Dayget_YearM5ptsYnT4ToolStripItemContainerKeyPressEventHandlerColumnClickEventHandlerDragEventHandlerCancelEventHandlerFormClosingEventHandler1ebjBxo88kPuZ3AThj4WjcONDotf6Wx4tJKDjeset_IconNatnNZozhvkysdyUMKDget_HandleVxeBCs4m94Rhg3A2vTXset_ImageImageoI7lep4oh5qk2cfr19wset_ListViewItemSorterr9SI1Xoq2u2grkVitxPBQa2dNoTACcLVCgTg5JyQLO5b44TiHNGZ10visEnvironmentget_OSVersionOperatingSystemSuR38y4Cox0XojZAmCXget_VersionStringdIoo9l4RjmDefsMWYDWCjeQaZ4ZojpqdiAwvl6yZYr4J4kimDOnfoZYyBget_StackTraceGt2R3s4lGdvj2i8DGqtE4b6tw40nlS2igNyd61aJsjRA4IPnYNAKnde74get_ColumnsColumnHeaderCollectionaLNsKi4p5Z4u35BDqMn6O5V3V4MVo22uuZp6yPset_Width7ocnmv4GKl64em5ODkEXBngie4xxNBx9DPgOaIFormWindowStateget_WindowStateJG0koS4fW8nW4LuNumeget_WidthoOUbYQ4PciPIXap0JSlMuFsoi4hTDAI4ubtJnGRmQ8i64BT1muyRVOrCd9jSwMg4ysq322tUChsvCommonDataDVDVideoSoft.Resourcesget_ErrorptMF7q4ernfZTgqnGLoMessageBoxShowoDKnVX4X0R9iWR16bfXITaskDeffoueBw4cnfkVnpayZjh7eeIAd4g0BbeUSX3JQRPathGetPathRootc7c5De4Ui02d1uQWJXHget_AvailableFreeSpaceFqr92R4Y72pO8v50Tp2get_ContinueMTqh2T4V4rAyHPigC6RMessageBoxButtonsMessageBoxIconIuBpaE4ajMgy9fDSkg3IsNullOrEmpty2l8Vmj4w3jeQ5uiaXEIget_OoopsNoFiles4crFQr4jtloZXAnEKKSget_WarningoBjFbI4u41epXVhNbFEget_LengthtQmThk45vJNYV8NvGfYget_Information1nN2HH42S2dJ37DXcRpxRh3T24A9gd32bjmGFHROrAac4LZ8qF6mknQFmTrimEndIJCqFu4bkDByxQnd2wGToLowersviOcN43W1fpyoo2k4tEqualsJ1gDh94QKK4V7a8cXrjeIp9ec47GN4BuwnKy3gDirectoryExistsGi02Rt4iJ3b4CZE8DyJ4huiqe4J3a4KD4f9esFop_InequalityZcR2qu4NrN8hZ6XEYkHkoXxwR4D2suWoRB1TZ4FileDialogset_FilterIndexSUiGPc4nODk2M7nEv6nset_RestoreDirectoryJd0REY4SxMoQHrF78CAset_Multiselectb74FxE4Or3JCyBJ3NoJset_FileNameExX7sX4r6X2aHw8L8KjYTyYjn4d94F48VZt09Aget_FileNames8C2KTG4WjZiiRM65AXsget_FileNamed5PIbM4KhN0ORPZL9ySQs0fng46e9E16qvxWpVset_VisiblevXf2Ou49hoixI3HAabTRefreshsOWVrb41ymyFeCioQI2ar5DKn4vSJsHQcV25oBuY6Q8O4sbc4a1xLSE4lset_TitleDT5Xa94EPbKlJjCTZHdset_Filterf9m1234FLRSU8UH1MmbFileSystemInfoget_CreationTime3A3CA94H44lusuY1j3VEvttVY4qMCxN86RANu5ListViewItemCollectionNQyomI4T2Zr9PscyigJget_Name0TAoGc48PAenoJdHFjRDteJkq4tLQNFfy9GGJwset_ImageIndexwVfpmi4zHsBO7Gt125v1QCPogCmCN25RCny37naqIKU2ColeVqBScTe8spGF0eGC4dHiWmkkAQjycApfpjCCmj7sd7I8t4Yset_AllowDropB0EJcmCRRq4HmZXJYutPushvZr3cHCZRcM6R7HP8Sce7q4YKCk2svjDrUdPmEPopKG0IlVClomTpgZKXjrYPeeksluwNZC0Zft3DV74xmeFileyA9Pm9CIaabOThN8hgOFocusyJZNrSCpMBM2aBeJRE7get_MessagemofpxXCMb6Cx6fx2QHlMoveNextvywtcECGXD3Z3u1FFwa17UOuDCxfnoPDE9swHHget_ColumnrkOYFVCf9QsJWDfGP00SortCYoql3CPDZJeycO2USCget_SelectedIndicesSelectedIndexCollectionolrGJ8ChNk81jfueM75GXN1QZCB2GXiFmq3IT4get_SelectedItemsSelectedListViewItemCollectionFyiSyvCyDbGaOBKaifywnvEClCeo7nr7K87xlAaJhIpJCXrRxodMfAL7JJ2UIEXCcmNTFUSqHdEGget_ForeColorrykpUlCgUAQivWOmK8Kget_SilverqKYgseCU3vYdyjrYeugqLtR4uCYQlDOMnjj1GWget_DataIDataObjecthbNWqrCVSFkGL6u2YwyGetDataNcOi2hCarW4FwNNboJQ9yKeI0Cw0kPWmlCZQ8OGetDataPresentV1kj93CjJ0QUc2uKxF3DragDropEffectsset_EffectOELvowCukdHS523bNUNget_KeyCharE1nniJC5xWnuNc7qElifHl3PFC2DZhZHHVjJR8RG5E5UCA14sRB7CYiv1suOoGXCLBLZZdjgXeCfu6NA4TCboqDj7fvJL6Pget_OKlHkTFvC38fajkJutiAMget_Canceluqr5HkCQchVdwhF4tiQget_Rename8pnOpcC7AmR0PWgeep4GQ7gm6CiKBXNJEi0XvyxLFimoCJK7HjrL2KQyaRuntimeFieldHandleRuntimeHelpersInitializeArrayArrayuiJCj6CN3KI6eMw8l0HIndexOfAnyYEkO2UCDUYkacJVBMx6get_BadCharactersr1ALZwCnp5gsTXtT7BgnWgvJmCSXpBFIwhUccIset_Focused8cJMnVCO8bXFMTawoYeT8Mlw4Cre3yuMVhEsRYClipboardContainsFileDropListjYW2fbCddyZolrXGMm3GetFileDropListvICLZRCW0bbx1tuIhnXyVmyu6CKgYSg2CqFstaVZQiwhC6d33uh32bjlPKkE4sLC9LpaOJKfBmyoCreateDirectoryDirectoryInfoIQWmKgC18h6EgAQYPkFget_NewFolderjATljnCvBZf3jcVNZt9c5vdRiCsjmmHLGZvLwoget_Chars2XgTGlCEn1nLoWEhPMnBeginUpdateRtkUgFCFtoyeUk01lS8set_SelectedBtNYXrCHgM27BKsw5QSEndUpdateGiln21CqQTbKLxiWEW6ClearyVH2XxCTE3X0le0VcbrGetLastWriteTimeuLsA1GC8MIy5fi6lMkvset_TagDfJalDCt1WvPr6uhu25ICollection`15t2jaeCz2GBHQopTe1UZXkLfERm48ZyvymYvbcQm6xqWRoN6xtsIfbYntQpo6rjR4FngQirtRTVgZUlN6pRCbfmga2pmU9rget_WantSolution1Bm42MRRrusLPjq5io4get_ConfirmSUX9lHRZCYYSvrZKqLCget_StartInfoProcessStartInfoJbI0uCRkOrgaOav2Xk6OqnBN3RlqCRWYPgVCdR9xZnCHR08KX0jXUaZI4ThreadSleepu5krvXRITTFr0viORGgExitlmaH20RptZ5GNaQ2qSxmeICveRM5mEDMbVTWMEget_NoDiscvoKXbVRGr877Zg2U0Haget_BurnerBusy70OcBaRxSjethnUIA9M0FAZ4mRfyEBHl5gbm6wEjectDisceJE5RDRP21Mwtgyujf4get_DriveBusyeRQIa1RhHhvakFy79q4OWhjMnRBfrfpgkVWXBRget_UserState98UxnmRyNmeUcqW5wTGget_ProgressPercentage7C6FV9ReFcko6wddXvKget_CancelledvtqCW0RXBB6F2coX33NMarshalSizeOfb0oPvWRcpxR6lWhPiJgFromHandleF6graXRg8ikHNVhuTWaCloneBMy8dsRUVeGCXKt2INJn6lrvHRYESWOF98oMXCIsBusywvAOX6RVysWDbUo6Jo6get_DragAndDropFilesHerepkS4SNRahqt38t9mYlEget_Red0R5OgVRwD5FdTecgKyXLf1txDRjJOWhD5aVIaQwFvDXBRuIZVUobcMHJh5uk67KR5EB7KYi2FNc5get_WhiteR527g1R2TG0uia3aWcTyuxY9KRAAI438gLk86Oget_LeftWHsdpIRLnnJWxbjttZJget_RightiPexBeRbPSqSSB10ctXget_Topu7keClR3imquGYUbyI0get_BottomaMRy7nRQexa9DG5rIunkPkrBFR7qMksqxVSd0DGetTypeBESV4KRiaklYlH1nG7ddBpDZwRJAt5KM1JoG2HvsO41sRNYWoVrs8YuFbget_DriveTB53tcRD0cl3ABiu0VMBringToFrontTBFjt5RnRWt2IwEuP9NSpecialFolderGetFolderPathORgHAyRSbUT2Stw1yG2get_ImagesImageCollectionbwV6CSROJcNETKwAWM9XPY24ORrXZAPtFFoCqwget_EmptyhDIjU9Rdsipw0EEZE55GetExtension83YucxRWEWMsIEinjUv2jksljRKPGn7CUyI0ExContainsKeyM8KkNTR6htyftRXbunao2DGNyR9jqFcR2DytR9IndexOfKeyyLqLD7R1xn8ZS6rr68sget_NowVGe3kiRvfv01Auo8wPyY7lx4mRsDIqibDLMmKejInvODREp782QLAp41DISupportInitializeBeginInitdqVJpARFufXAVYgTNOEVlqnIgRHEIkaA1EuANRpiOUFJRqXCtkWdlOgrn9fBMJSRTTh1vFoonHxkDirBwDR8ccf9MIGDglpmp4lKaRtIwciQkEMYqTt3qTChRzPFSYjrd48vi8RTxvDZmVVcULgBSVvou7bbOrZoXN5qvNKdR11I3UIEVZ4nQy3whq4Mw2FromArgboiUAMFZC9p2cFBOMoD6BorderStyleset_BorderStyleKKQpOhZRpG9w7UGRhnZset_MinimumSize0W9aAwZZN5370I3efKsget_SteelBlue4MZ7d9ZkNyWSMuPSYDyset_TabStop1W9Y0LZl4SahCK5nIddget_WindowOtWGHaZ0HwICC6qYG6n5N91DbZId2e5eIwISQgAddRangeCbPrLxZpWFwsBfXJAaDset_ContextMenuStripamPNRtZMIB0nygkkP2gset_FullRowSelectjihmV7ZGYS5ZML2g0Cmset_SmallImageListWu5ATfZxa08xG1mosV7set_UseCompatibleStateImageBehaviorIxKaSLZfqPeabQL5o47Viewset_View4k54QTZPFEfc9uGPLG0add_ColumnClick77yTAMZhJCOWdC7v4jgadd_DragDropUuF1iwZBDGF8uTCdTWQadd_DragEntervLyYUJZyRBdBBqTqupCadd_DoubleClickOkGRLAZe9jFcWOrWVsEadd_KeyPresspmfOdEZXPmGCPoHC8SuToolStripToolStripItemCollectionYGbsufZcrbIhKOmmEg1XKMR9LZgME0dEQ7HVUrToolStripDropDownadd_OpeningXk9hdbZUfAMW8mrXUlQe5XhUZZYS9OKPvHCLui3h2oPfZVvyan7Y9yjWDToolStripDropDownItemget_DropDownItemsC8MaaJZabmS8eWcjl7MColorDepthset_ColorDepth5ds1gJZwpAdOdP3AVBoset_TransparentColorKO5M7RZj9tvelE2hY4MLZGZsTZuAw2RwSv1tpDc9OK4mZ5FGYVQk9pnp0X5ZgtjZ2GyLM5TQQMQiget_ControlText4DRBVBZAa89AvCVjs2mget_Maroont9pm9qZL2NS7VOicoQJMPWW98ZbtJ5TyWMrTu4AeIkInZ3U0a48l9HyPIsFPrJkZQOjbZwuL8cpxadd_FormClosinge2X2yqZ7koBKdOZaAOoEMDrZXZi9aC8YgxgnYSadd_ShownBCKaPuZJSfHkn4u7NIvadd_ResizeIPPeoSZN4FiLbFyXTHcUWB2jkZDG63FTHNNDEDv7hjErZnO1c57JFBja7EndInit5LKtLJZSBgdWxa8gnVJRecorderIndexDiscTitleSpeedIndexCDSpeedDVDSpeedEjectFinalizeDiscISO9660CheckJolietCheckUDFCheckTempDirectoryWindowStateSortTypeIndexSortReversColumnWidthSplashErrorReportFormBitmapStreamShowSplashSetSplashGetHumanNameGetProgramPageUrlSubstringset_ProgramPageUrlSubstringIWin32WindowCaughtAndHandledExceptionYlZPbCZ9JH4UoSikBYBEnableVisualStyleseLHrKiZ1YxbTWXLx3MpSetCompatibleTextRenderingDefaultIWfYA1ZvMOCwGFmMh8ZwM7usJZsgfGxP2Uk2QdGetExecutingAssemblyO7RY8AZEXFgGWMJpkF5GetNameAssemblyNameQasp5xZFkFXJTPL1wQAN84retZH6bTn0TneVrcoFG99TZqcngLkSGbntvJovZKnZTsPbApYuavlLGetManifestResourceStreamcobZZ2Z8rrKwMxhQHdJClosehppi7jZtuhNlhmkWYnO2p7dvGZzJGQh5KDTT0FuZUvrGkmCX7X0IiNiVERun6cr3pLZKP8FoVgyb1AZVPSuVFZ6KdwsEoxkuRQget_backcolorget_MainIconget_ProcessIconget_Success1AD2l9kCxDniVixaws6mmq4WqkRrId4gXBnu71sV477bko8hZpDc5DrYhFmvLa5k47hl2rmMrCjmU5f8wTkZrcDU3mYsZX0hbkmRMkkKXfOLbYD0GyqZrhaPklHb3EbWWYWQWGetObjectbackcolorMainIconProcessIconSuccessdefaultInstanceget_Default.cctorP9WBx3kpmTdX1NgtHnS1xVOChkMxYkDAV5w6woH3ec1Nk09ywBM5Pm6YO67SEhDkIrC0JEAXMmphQWa6mGkGonDlZV54NgRSettingsBaseSynchronizedDefault$$method0x6000052-1$$method0x6000056-1ij0fPFSST4bmVtypemdtFieldInfoMethodInfoGetFields9TcgGukcL7ZuWN6c9ykModuleResolveTypeHEWcQ1kgixdWCRBF6vPMemberInfoget_MetadataTokenwokhWEkUNk9HuRAGLt2ResolveMethodMethodBaseagan3YkYHZf6MWC40t4CreateDelegateU8kwD3kVGlA59Uat54eSetValuegeF8OHkeUbFuoFevHrXyZ4prKkXVqOis7Db7ATlB5dwbkahbkcrHXyRaGX2H58pkw1B5DfwsGZwNc6tsmskjglssXWprJOrJyjFy1kufMi4UbD6XxQget_ManifestModuleobjectmethodoBeginInvokeIAsyncResultAsyncCallbackcallbackEndInvokeresultDictionary`2ByteZeroSortedListHl2fPFS7Kt8UPCryptoStreamSystem.Security.CryptographyBinaryReaderICryptoTransformMemoryStreamRijndaelManagedCryptoStreamModeTrimFromBase64StringEncodingSystem.Textget_UnicodeRtlZeroMemorykernel32.dllVirtualProtectFindResourceRSACryptoServiceProviderset_UseMachineKeyStoreget_Locationget_CodeBaseReplaceGetPropertyPropertyInfoGetValueLoadLibrarykernel32GetProcAddressWriteProcessMemoryReadProcessMemoryOpenProcessCloseHandleFileStreamFileModeFileAccessFileShareReadRijndaelCreateSymmetricAlgorithmset_Keyset_IVCreateDecryptorWriteToArrayha01grC4JXN2Uqr2MKcQjZnQBV1jGYYw7RELQcZQxnZs0BqAQQfmxmget_BaseStreamyWHcNB7XvV1PxdHa1Xset_PositionFHAIx3lSrGvkq2b1bueDd4ML0SJCvAfJ1koCEJJVOjYrJSJn4VNW16ReadBytesO50qtqcmbNArjMh0cSjI0DVKMLCOkNwvEdO0GetPublicKeyToken1JciIg8QKTGPAmpWiyCipherModeset_ModeHRGtKQns9cP3hRuITtm38gbT6OXwvS4bmSfrMyVHSjKkqkDweJBKljFlushFinalBlockLbiyerkW0XoiPZK5oWffZXESs4wZUtFM2gYgrLFpUnJdMLcSX8XO14JN93CiI3QAgex6MxhtBitConverterToInt32bRwfGdQL09JcHt1RBAop7am1w4BpLWDlnMxUdaLj5coEvGdnXc6ottBVjSx742YLEqgZdWUnmo40Wvkbc783wEKaawMxpHdXhk32Td3qutDpQTGGh53ckQqqXb4PuuYhMampwR1k78ItGPfYn13sTce4DmfsmSrOT856tDgfrkMbMD5MD5CryptoServiceProviderntKnRpkNS9BfMRHvY8Mab8AlekDb9TH043iy3gh0AnWUknSc2Sk3pNgUgAZ1ue5kSLAXPe7Z6NpLToBase64StringlgtGmskOYR8OrPIrIxkCfMBcUkr09SK5qttix8HmeglSkdvmNPKn7CyMETpHMMmkWtmJB8PCJnuJOeWXq5kKwy6NQKV9otRGetByteskk3oLAk62bvq6S1vy5U9Bh4dZk91vTJ797GSvSHashAlgorithmComputeHashoghHWnk1wN97hUEND5Op6dZVGkvwuglqnwGh8NSVaPNvksWXkm8qJgQQ5J0illukEQBpDQojemcPCreateEncryptork4ZQZvkFZUWay5XAX39xNWoS8kHMHHr06DcZVqRdodyNkqxfX3PVNxFO8aVBgrikTHyGM3mMA7sWU7KjQtk80PMFB0LSpo1UInt64BLSfPFSzsDwJNApIEQGl0oLXv0FlZWmbAppDomainResolveEventHandlerlLHifFIsCLsZtjvFfN0iResolveEventArgsHashtablehsnrl8lM9CSXQoWGemUlPm2tvlGCBHrIgefkuHget_CurrentDomainFTxbnplx12J1IQ6b4lKadd_AssemblyResolveJLWjjHlfeUkZ6XLuDuRi8a6G7lPR5smVx5kVoPRGfNbelhyRaYudrTlpUn5Np5XlBkFxmn2u4Yp8V0giKdlya250c17voElhWcdT8let4Kvg2c1oB4Jf4kU0lXGHE5AITq0OANfN9I6lcQcuNaXgI1HoNA7Cdllg0wmNFxFmIYMZRLCLOlUvwKYmMt8KVxQXl1rdlYgNNnWXNm22hS6lGC4lV1SiCaQDfPvP4wEcIHlaWJSNXA4i0dKIO4xUXlwWBDKlMejgr0XYOudyljTIodwyctRXhu5wjqbluAjOOETSv4mrNW6ONVl5AUfMPr1267kLoadSk8GbBl2t16A5WELPEqget_FullNameIJRYSnlA3S9O8silgkjbBZ0n0lLGFwloEP9y6dIndexOfp9GlXVlbKAVeQMjwYvWSubstring$$method0x600001d-1$$method0x600001d-2$$method0x600002c-1$$method0x600004e-1$$method0x600026c-1$$method0x600026c-2F9XKeOl6vlxourFpsvQFreeDiscBurner.OptionsForm.resourcesFreeDiscBurner.StringResources.resourcesFreeDiscBurner.FormDialog.resourcesFreeDiscBurner.Main.resourcesFreeDiscBurner.Splash.pngb0494a1f-4bd3-OQGXfPVcwg2d75cuk72jxA==b0494a1f-4bd3-8hSeRGHzYDNVylaB3fVqJw==b0494a1f-4bd3-WdfsM593UCNoh0skiaZkSA==b0494a1f-4bd3-kALMiogkM4LGqE/oOd133w==b0494a1f-4bd3-B8e77awqlfNfi73OsSxdlw==b0494a1f-4bd3-R8THV6v22cqqeGO/hwTzqQ==b0494a1f-4bd3-ZE393gnYXN7OQ1PNT58exA==b0494a1f-4bd3-C644nPIhe0AMNlVlKwsM+A==b0494a1f-4bd3-b36YZ1u0g+/+nDMS2fpicA==kKVTf7nGiopt385jtF.BCmqKe3r570WwZbTqSb0494a1f-4bd3-hCcw3DrxsSV6N7tUvMVbVg==b0494a1f-4bd3-5sEs3rs4gds65/u5layTQw==aR3nbf8dQp2feLmk31.rFohpatkdxsVcxLfJKhM7.resourcesaR3nbf8dQp2feLmk31.lSfgApatkdxsVcGcrktoFd.resourcesFreeDiscBurner.Properties.Resources.resourcesCompilerGeneratedAttributeGeneratedCodeAttributeSystem.CodeDom.CompilerDebuggerNonUserCodeAttributeEditorBrowsableAttributeEditorBrowsableStateUnmanagedFunctionPointerAttributeCallingConventionFlagsAttributeSTAThreadAttribute=FreeDiscBurner.StringResourcesGFreeDiscBurner.Properties.ResourcesKkKVTf7nGiopt385jtF.BCmqKe3r570WwZbTqS3{11111-22222-50001-00000}file:///Location3{11111-22222-20001-00001}3{11111-22222-20001-00002}3{11111-22222-30001-00001}3{11111-22222-30001-00002}3{11111-22222-40001-00001}3{11111-22222-40001-00002}3{11111-22222-50001-00001}3{11111-22222-50001-00002}QIIMۑz\V4TWrapNonExceptionThrows   Free Disc BurnerDVDVideoSoft Ltd. Free Studio)$Copyright Вc DVDVideoSoft Ltd. 2010 )$75960d3a-79e1-4dbd-b2aa-948c5e9df486 3.0.6.920 en-US MQzyara-4.5.3/tests/data/3b8b90159fa9b6048cc5410c5d53f116943564e4d05b04a843f9b3d0540d0c1c000066400000000000000000000533101501365277300250270ustar00rootroot00000000000000MZ@ !L!This program cannot be run in DOS mode. $PEd `"    `q@@@ @`"4 H.text  `.rsrc`@@@.reloc`"@BH7P AlSystem.Resources.ResourceReader, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089#System.Resources.RuntimeResourceSet%PADPADPiEx['x q4`t?|iy%F nn[&%*O0--3g4x=k><2/?T3CDB/FyH@MGY"au%bhJ>v'{X   KAo"GOWuj- + pCanOnlySetFocusScopePriorityOnAnElementThatIsAFocusScope@CannotAddAtomicUnitToUndoManagerHlCannotAddUndoUnitsToAnUndoContainerThatIsAlreadyClosedPCannotClearFromWithinAnOpenUndoContainer8CannotCreateWorkspacesFolder8CannotEndClosedUndoContainerBCannotEndUndoContainersOutOfOrderBCannotEndWithoutOpenUndoContainerFCannotModifySealedUndoUnitContainerCannotNestAdds$NCannotRedoFromWithinAnOpenUndoContainer~NCannotUndoFromWithinAnOpenUndoContainerRCantRegisterADependencyOnANonexistentTaskXtCantRegisterADependencyOnATaskAtALowerPriorityThanYourself@CantRegisterTwoTasksWithSameNameJCantRemoveATaskThatOtherTasksDependOncTConvertBackNotImplementedOnMarginConverterLConvertNotImplementedOnMarginConverter&DocumentAlreadyOpen+$DocumentIsReadOnlyVJDocumentNotIncludedInOpenDocumentListDError_ConverterFunctionNotDefined1DError_InsufficientSourceParameters@Error_InsufficientTypeParameters*HError_TargetAtOffsetNotExtendingTypeQ:Error_TargetNotExtendingType18Error_ValueAtOffsetNotOfType*Error_ValueNotOfType10InvalidTargetSubPropertyBMethodOrOperationIsNotImplemented6HNoConvertBackForValueToIconConverterm RedoStackIsEmpty UndoStackIsEmpty&UnexpectedBrushType*UnexpectedDrawingType2UnexpectedImageSourceType ViewAlreadyOpen> FFocusScopePriority lässt sich nur für FocusScope-Elemente festlegen.fEine Rückgängig-Einheit des Typs "Atomic" lässt sich nicht zur Rückgängig-Verwaltung hinzufügen.fRückgängig-Einheiten lassen sich nicht zu bereits geschlossenen Rückgängig-Containern hinzufügen.eDer Rückgängig-Stapel lässt sich nicht aus einem geöffneten Rückgängig-Container heraus leeren.BFehler beim Zugriff bzw. Erstellen des Arbeitsbereich-Ordners: {0}REin geschlossener Container für Rückgängig-Einheiten lässt sich nicht beenden.iContainer für Rückgängig-Einheiten lassen sich nicht beenden, wenn ihre Reihenfolge durcheinander ist.RBeenden ist ohne geöffneten Container für Rückgängig-Einheiten nicht möglich.LVersiegelte Container für Rückgängig-Einheiten lassen sich nicht ändern.XAufrufe für das Hinzufügen von Rückgängig-Einheiten lassen sich nicht verschachteln.sWiederherstellen/Wiederholen ist aus einem geöffneten Container für Rückgängig-Einheiten heraus nicht möglich.cRückgängig ist aus einem geöffneten Container für Rückgängig-Einheiten heraus nicht möglich.ZEine Abhängigkeit lässt sich nicht für Aufgaben registrieren, die nicht vorhanden sind.hEine Abhängigkeit lässt sich nicht für Aufgaben registrieren, deren Priorität geringer ist als Ihre.CZwei Aufgaben mit identischen Namen lassen sich nicht registrieren.TAufgaben lassen sich nicht entfernen, wenn andere Aufgaben von ihnen abhängig sind.9ConvertBack ist für MarginConverter nicht implementiert.5Convert ist für MarginConverter nicht implementiert.)Das Dokument "{0}" ist bereits geöffnet.)Das Dokument "{0}" ist schreibgeschützt.NDas Dokument "{0}" ist nicht in der Liste der geöffneten Dokumente enthalten..{0} ist für diesen Konverter nicht definiert.'Converter erfordert {0} Quellparameter.%Converter erfordert {0} Typparameter.>Zieltyp bei Versatz {0} muss sich über {1} hinaus erstrecken..Zieltyp muss sich über {0} hinaus erstrecken.2¬Wert bei Versatz {0} muss den Typ {1} aufweisen. Wert muss den Typ {0} aufweisen.Ungültige TargetSubProperty.5Die Methode oder der Vorgang ist nicht implementiert.,Kein ConvertBack für ValueToIcon-Konverter. Der Wiederholen-Stapel ist leer.!Der Rückgängig-Stapel ist leer.Unerwarteter Pinseltyp {0}.Unerwarteter Zeichnungstyp {0}.Unerwarteter Bildquelltyp {0}."Die Ansicht ist bereits geöffnet.lSystem.Resources.ResourceReader, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089#System.Resources.RuntimeResourceSetPADPADPQ-iG֮+RSNDocumentGroupTabItem_CloseButtonToolTip:StudioBook_CloseButtonToolTipDStudioBook_CloseGroupButtonToolTip'Dokument schließenPanel schließenEGruppe schließen ("Umschalttaste" halten = Aktives Panel schließen)BSJB v4.0.30319l#~#Strings#US#GUID d#Blob %3%B_x <<<!<)<1<9<. $.7.7.#$.+=.37.;U  (UmscorlibSystem.ReflectionAssemblyTitleAttribute.ctorAssemblyDescriptionAttributeAssemblyCompanyAttributeAssemblyProductAttributeAssemblyCopyrightAttributeAssemblyTrademarkAttributeAssemblyFileVersionAttributeSerif.Windows.resources.dllSerif.Windows.resourcesdeSerif.Windows.Resources.ExceptionStringTable.de.resourcesSerif.Windows.Resources.StringTable.de.resources ^,xNVpZ3z\V4?OD ?YZ   Serif.WindowsCopyright © 2014 1.9.1.9430HX@4VS_VERSION_INFO  ?DVarFileInfo$TranslationdStringFileInfo@000004b0DFileDescriptionSerif.Windows4 FileVersion1.9.1.943XInternalNameSerif.Windows.resources.dllHLegalCopyrightCopyright 2014`OriginalFilenameSerif.Windows.resources.dll<ProductNameSerif.Windows8 ProductVersion1.9.1.943< Assembly Version1.9.1.943404 *H 4041 0 +0L +7>0<0 +70 0!0 +ܘXz@3Sg&A v00Ơ+VQZG|<}=0  *H  01 0 UUS10U Symantec Corporation10U Symantec Trust Network100.U'Symantec Class 3 SHA256 Code Signing CA0 190411000000Z 220517235959Z0v1 0 UGB10U Nottingham10U Serif (Europe) Ltd10U Serif (Europe) Ltd10U Nottinghamshire0"0  *H 0  *[1 ̬# FV;"8A8# <5V8yYUe[zʯ#,LH[S(z4ӀehK8^K/Wn[m\X~Zj՝Qh,׆[|~1i\bh,G]iFVV(T2+a]JN,Gٸ=_S.0ѵnRv'Ĺ]0Y0 U00U0+U$0"0 http://sv.symcb.com/sv.crl0aU Z0X0Vg 0L0#+https://d.symcb.com/cps0%+0 https://d.symcb.com/rpa0U% 0 +0W+K0I0+0http://sv.symcd.com0&+0http://sv.symcb.com/sv.crt0U#0;Sy3}.+ʷrf0U喌sw@WDb)mp0  *H  1gtMP /Y>W~t %0bMްym.1Rݠ -0ޢ{^7#):Qĥ[0;ǭC ~#[pY,[GdS<8/p9q]r =mX4;;3`<$(Yq1(->_!5d&Lu51/]kEx"}" «m0:n[ėKc00 BJ:`@!0  *H  0r1 0 UUS10U  DigiCert Inc10U www.digicert.com110/U(DigiCert SHA2 Assured ID Timestamping CA0 210101000000Z 310106000000Z0H1 0 UUS10U DigiCert, Inc.1 0UDigiCert Timestamp 20210"0  *H 0 agŊ EckQ:B uuM P&ok \HD忛abZg c6j)+pxm}m =jv銽]vvv:SZ6ƣ/:asNm3|]E-KPA:7Vܓ#P%dӏ/W ,#MxF1)J\ 1J0Z_lCI &#Sc[0›iVTz[ /K ɕcNrzs I00U0 U00U% 0 +0AU :0806 `Hl0)0'+http://www.digicert.com/CPS0U#0 )a%5n0U6Df(-D6jz0qUj0h020.,http://crl3.digicert.com/sha2-assured-ts.crl020.,http://crl4.digicert.com/sha2-assured-ts.crl0+y0w0$+0http://ocsp.digicert.com0O+0Chttp://cacerts.digicert.com/DigiCertSHA2AssuredIDTimestampingCA.crt0  *H  Hܵ# gFBrQt #G%pY'MyÆ;DfMipbQJxy6z'RC{A"FNdwc_#RiS̍s e9pKz{ =2auv\rdI"uB-28`R\a$%O)sCQڽc[.OJ q~?IΧVϺYva_~gx6([/010 %2~A60  *H  0e1 0 UUS10U  DigiCert Inc10U www.digicert.com1$0"UDigiCert Assured ID Root CA0 160107120000Z 310107120000Z0r1 0 UUS10U  DigiCert Inc10U www.digicert.com110/U(DigiCert SHA2 Assured ID Timestamping CA0"0  *H 0 2K͏ݩ9T(W#JE3Q}}Mh~綠􍳈䗿c!W~j8.;̦2Y_e?FGU~ '~"?~">m;| ]Ț T qk"uqrN @:\QyM$#0]<`j/GوP^fnVa')QFP*,u>1֭d{Єr=MBS*O<ڬݬV00U )a%5n0U#0E뢯˂1-Q!m0U00U0U% 0 +0y+m0k0$+0http://ocsp.digicert.com0C+07http://cacerts.digicert.com/DigiCertAssuredIDRootCA.crt0Uz0x0:864http://crl4.digicert.com/DigiCertAssuredIDRootCA.crl0:864http://crl3.digicert.com/DigiCertAssuredIDRootCA.crl0PU I0G08 `Hl0*0(+https://www.digicert.com/CPS0  `Hl0  *H  qQVi|czx7@Kŧ B,w+ !Z*4j'f `v:|b^%ĺ{,![,5Churǘ٦V?.)|=꺓P")L:_֤%k/L'{ "`?MLrgw'Ǻ5I(J D 6+P]'KT+^t É"wCL?d!10001 0 UUS10U Symantec Corporation10U Symantec Trust Network100.U'Symantec Class 3 SHA256 Code Signing CA+VQZG|<}=0 +p0 +7 100 *H  1  +70 +7 10  +70# *H  1;-hRa֐I}`0  *H 0C"ܦ>OxRCkD"Fr4Ńc_y%6?I^%;'{\GSn}q4!#WDoz<ӥAkkkK9 G%}/965si8::Ltw8X ^ 7] [ZXi&xmXdDY> ?00Ơ+VQZG|<}=0  *H  01 0 UUS10U Symantec Corporation10U Symantec Trust Network100.U'Symantec Class 3 SHA256 Code Signing CA0 190411000000Z 220517235959Z0v1 0 UGB10U Nottingham10U Serif (Europe) Ltd10U Serif (Europe) Ltd10U Nottinghamshire0"0  *H 0  *[1 ̬# FV;"8A8# <5V8yYUe[zʯ#,LH[S(z4ӀehK8^K/Wn[m\X~Zj՝Qh,׆[|~1i\bh,G]iFVV(T2+a]JN,Gٸ=_S.0ѵnRv'Ĺ]0Y0 U00U0+U$0"0 http://sv.symcb.com/sv.crl0aU Z0X0Vg 0L0#+https://d.symcb.com/cps0%+0 https://d.symcb.com/rpa0U% 0 +0W+K0I0+0http://sv.symcd.com0&+0http://sv.symcb.com/sv.crt0U#0;Sy3}.+ʷrf0U喌sw@WDb)mp0  *H  1gtMP /Y>W~t %0bMްym.1Rݠ -0ޢ{^7#):Qĥ[0;ǭC ~#[pY,[GdS<8/p9q]r =mX4;;3`<$(Yq1(->_!5d&Lu51/]kEx"}" «m0:n[ėKc0Y0A=xvI`a}ʆ*0  *H  01 0 UUS10U VeriSign, Inc.10U VeriSign Trust Network1:08U 1(c) 2006 VeriSign, Inc. - For authorized use only1E0CU٦V?.)|=꺓P")L:_֤%k/L'{ "`?MLrgw'Ǻ5I(J D 6+P]'KT+^t É"wCL?d!10001 0 UUS10U Symantec Corporation10U Symantec Trust Network100.U'Symantec Class 3 SHA256 Code Signing CA+VQZG|<}=0  `He0 +7 100 *H  10 *H  1  +70 +7 10  +70/ *H  1" 1 ؚEU1AEBBS@03r0  *H U9wOXmsU=EW&t6wIeN@N7DOk~Efo߽d> VND-8e"5:k݋S">9Yt~~ϒ㷶58ȎpURv[43=ZH:W?بҖ2=*{bM@?<Ei3,p@TvxEEIwV0j q[bϳ^PVDV'Psa‘5ھƗ:9i<08 +71(0$ *H 01 0  `He0 *H  0 `HE010  `He :'aɭ7ć[ Y4)+fdqN9fE|;20210206230923Z001 0 UUS10U Symantec Corporation10U Symantec Trust Network110/U(Symantec SHA256 TimeStamping Signer - G3 080 {IhQDɉҜ0  *H  01 0 UUS10U VeriSign, Inc.10U VeriSign Trust Network1:08U 1(c) 2008 VeriSign, Inc. - For authorized use only1806U/VeriSign Universal Root Certification Authority0 160112000000Z 310111235959Z0w1 0 UUS10U Symantec Corporation10U Symantec Trust Network1(0&USymantec SHA256 TimeStamping CA0"0  *H 0 YYUOr]UM 3I;Kሙ3ǀۑWrwͨ 7jK _y5x2#2AY>+m:ɜHS6xš7w0s0U0U00fU _0]0[ `HE0L0#+https://d.symcb.com/cps0%+0https://d.symcb.com/rpa0.+"0 0+0http://s.symcd.com06U/0-0+)'%http://s.symcb.com/universal-root.crl0U% 0 +0(U!0010UTimeStamp-2048-30UcʣNrৼA)8ub0U#0wiHGS2vї0  *H  u-4\2EOxoOȁ@)]Vdq0*af V]q G̐/ lN3ִLcH9@!n< ɏSWA/MNxlBna\RNkJzS uu.fW:Ί۞8R` M'm2?@Ῑ9+ZXU}ǚ#*a0K03{寺?#"AM0  *H  0w1 0 UUS10U Symantec Corporation10U Symantec Trust Network1(0&USymantec SHA256 TimeStamping CA0 171223000000Z 290322235959Z01 0 UUS10U Symantec Corporation10U Symantec Trust Network110/U(Symantec SHA256 TimeStamping Signer - G30"0  *H 0 ܿi{TqG e$ m0?'J3Nm@" <$(rQ= &:C#uGp _[rHWeM<@28?,Y#ˀMɪ lUaW,ĵl#ҟ lbiNR1[tRWl"Uo?J"ve6򖕁&,8ӯ%@ S)WX^HA!޴&{@SXyR1ME<:"Ŵoﰊ00 U00fU _0]0[ `HE0L0#+https://d.symcb.com/cps0%+0https://d.symcb.com/rpa0@U9070531/http://ts-crl.ws.symantec.com/sha256-tss-ca.crl0U% 0 +0U0w+k0i0*+0http://ts-ocsp.ws.symantec.com0;+0/http://ts-aia.ws.symantec.com/sha256-tss-ca.cer0(U!0010UTimeStamp-2048-60Un_;1y6{0U#0cʣNrৼA)8ub0  *H  F_HϨ'K!Ͳrpc/U){9FN~eXW 6$ {;bJۊTm(gq?3 ٢YJekR)uJ+˛MYA÷?Dz"tG %t`n`Vz DXHwr$,?Kg_\T>3[ŷNqfE?v1Z0V00w1 0 UUS10U Symantec Corporation10U Symantec Trust Network1(0&USymantec SHA256 TimeStamping CA{寺?#"AM0  `He0 *H  1  *H  0 *H  1 210206230923Z0/ *H  1" L%<(hnr#3c4#eM07 *H  /1(0&0$0" tv}9N |ƀ^86ADOhP zf7P+Wjeٙk.ﲂ3y lzhT:h9v s;/|}-ƅ]f}zYh6mͪ)LQ8YmSLT>m2ubҿk$|GTd-"| [RLJ G`ܙp|*1+.; &pom7&qyara-4.5.3/tests/data/6c2abf4b80a87e63eee2996e5cea8f004d49ec0c1806080fa72e960529cba14c000066400000000000000000000037041501365277300255140ustar00rootroot00000000000000MZPEd 8@ @Fu `U.text@@ `.data``.debugU````bUHVWH0HHuHHHB`HHBXHH HHftmH5vHftft W HfHDf?uHWH$uOHHE fuGHHEHO1H0_^]UHAWAVVWSH(IHHHxhtIIH11HPpHHuHHHH;xhrHH@pHD0IE1LH([_^A^A_]UHVWH0HH}HHHIP@H?HtHkHHE1hHH0_^]UHH V]UHE1E1BB+A IIuE]UHAWAVVWSHHHE HPH >HHmledHHFLEIHFHEH3HEEHH J1@HHMHULEQIHHOI9E1u-Mԅt&IHHMHULMMQIMANHHbHFH~twIN1Y8AH^D;HH^HD;AH^D;FH9s;HFHHH HH|LMttHLPH HLHuLPHHxJHHH\H Lf1@H?HHMIE1HHHy HHPHHHH[_^A^A_]UHVHHt,qLX HtLIHE1C8tIL9uL?H:C|u2H Ht&KTAAC|D0DHA ^]H^]xCJObA}Rs?)H^ D3;]1DF>8=J6@aF34#L9wד:'?Mc9||MTOCD<\;nF0U2AC71AF3-A338-495C-834E-977A6DD5C6FDyara-4.5.3/tests/data/756684f4017ba7e931a26724ae61606b16b5f8cc84ed38a260a34e50c5016f59000066400000000000000000102450001501365277300247720ustar00rootroot00000000000000MZ@PEdI" :B!@ha ت H.datah@.xdata@.textD+,j `.extjmp  `.extrel  @@.reloc @B8:BA:B9:BI:BQ:BY:B0ʐ:B(x:BА:Bu`:B0:B :B:B:B`N:B0N:BH:B%:B x`j :0dHP(X!PX @6P9 <ЍX(t(x:B:B@%:B77H:B(:B:B0:B.h X:B :B a:B:Bpoo:B#:B:BU:B:B:Bxթ:Bϩ:Bʩ:BP:B!:B:Bg:Bt:BO:BO:Bh?:B:B`:B:B(:B8.:B`d:B0T:BV:Bt:B`:Btt:B:Btt:B:Bt؏:B͆:B2v:B:BB̆(u:B :B2@v:B@:BB̆Pu:B`:B2:B:BB̆p:B:B2:B:BB̆H:B:BB̆:B:B؆0:B :BB̆ :BP:B2ؔ:Bp:BB̆В:B:B2(:B:BB̆:B:B2P:BYD:B:BYD蕏:B0:BYDh:BP:BYD:Bp:BYD藏:B:BYD:BA+v:B:BA+v:B:BA+v:B:BA+:B݆pt:BP:B݆Ht:Bp:B݆:Bu:B:B8:B:B蓏:B:B:B:B+p:B0:B+(w:BP:B+w:Bp:B+8:B:Bu:B:B:B:B`:B:B:B +Ș:BنX:B͆xu:Bp:B͆u:B:B͆H:B:B͆:B:B_YD`:B:B_YD:B:B_YD:B0:B_YD0:BP:B_YD:Bp:B_YDȐ:B:B͆ :B:B͆:B:B͆p:B^YD:B:B^YD:B0:B^YD@:BP:B^YDX:Bp:B^YD:B:B^YD:BWYD0:BQYD:BPYDX:B :B:B:B:B:BP:B0:B:B:B0:B:B:B:B:B0 :BF:Bh:B[:B[:B:B&:Bǘ :B(:B9:B[p:B&:B񨅏:B\X:B78:B&:B v:B vP:B:BX(:B:BG:B8:B[୩:BP:B':B :B:BE:B9h:BΎ8:B@(:B9:B9ȴ:Bp(:B7:B:Bђ:B2x:B(:B(@:BC[ƒ:B):Bv%(:B֨:B;P:BH):B(:B)Lڃ⃎:Bn[xĩ:Bvũ:BϏũ:BpEƩ:B xǩ:B ȩ:B-ȩ:B *:B1[:B8*:Biɩ:BP*:BŨhɩ:B*ɩ:B*:Bc%ʩ:B*:BgEp̩:B*:BLڃ":B*:BhΩ:B)ϩ:B*:Bb%ϩ:B+:BLڃB:B(+:Bgө:BdEө:BdXԩ:BPԩ:B\%xթ:B+:BPש:B+:B)[b:B9(٩:B+:B٩:B,:BΎک:B,:B ۩:B ܩ:BPܩ:B90ݩ:Bx,:Bݩ:B,:B"[:Bߩ:B,:B9:BWE:B&:B-:BW:BT\0:BΎ:BP-:BS\:B8@:BΎX:B-:B8@:B8P:BP:B[:B:B :B(.:B8:B@.:B[„:Bx':B :Bώ:B=%:B.:BqPx:BJ(P:B:%:B/:B.Y:B/:B`:B:BH/:B(:B`/:B:B `:B(X:B/:Bx:B:B/:B}Տ:Bg:B0:Bp:B 0:B:B[Px:B6:BxՏ`:BXP`:BV:B9P:B P:B(:B\̎P:B(:B(1:B$[:B@1:B9h:BX1:BOP@:B,:B :B1:B"D0 :B1:BLP :B% :B%P:B2:B8(:BQ(:B:B懏:B㇏:Bx2:B_Տ:B>P:B[:B2:B>Ϗ:BE:B>&:B3:B-:BCh:BH3:B~:B`3:B=&:B:B@p:B3:B %:Bׇ :B$!:B3:B[ℎ:B %#:B=h%:B84:B':B((:Bh4:B*:B4:B@+:BЇ,:B4:BBΎ@:B4:BY!`-:B4:BLՏ8.:B/:B5:B/:B(5:Bc/:B@`0:BX5:B01:Bd91:B5:Bp2:B2:B5:Bp3:B(4:B!Ɏ4:B[5:B6:BY6:BH6:B[7:Bg P8:B88:B:Bb ;:Bs@:B;:Bdx<:Bx=:BE=:BP>:BP7:B-Տh?:BH@:BF9A:BfvA:BS `C:BC9C:B7:B &D:B!F:B8:BΎF:B(8:BcvhG:B PG:BX8:B@9`H:B((I:B[J:B8:B(K:BPM:B!M:B8:BՏO:BՏO:BEP:BEQ:BR:BRv@S:B[S:BՏ0T:BU:B9:BLU:B9:BՏV:BPW:B::Bv8pX:B[pZ:BP[:BP::B,[:B2\:B%:B.^:B::B :B::B(a:B::B2 c:B%`d:B(f:B(;:Br:B  s:BX;:Bs:Bp;:B …:BP:B;:BPh:B;:B:B :B;:Bh:B (:B<:BX:B:BH<:B:B:B9`:Bs:B<:B욄0:B[:Bn8:B<:B<X:B3v:BD :B8=:B~:B}[:B㚄~:B=:B|[b:B⚄}:B[}:Bq`|:Bܚ{:BK0{:B>:BQ88y:B(>:BΎHx:BΎXw:Bp[B:Bp>:B(u:BՏt:BV `:B>:Bq:B p:BPXp:B?:B o:BΎn:B0?:Bk0n:BF88l:B`?:B[k:Bx?:Bi[":BE8i:B?:B%g:B?:B?:BH?:B?:B>:B>:B>:B>:BX>:B@>:B=:B=:B=:B=:B=:Bh=:BP=:B =:B=:B<:B<:B<:Bx<:B`<:B0<:B<:B;:B;:B@;:B;:B::B::B::Bh::B8::B ::B9:B9:B9:Bx9:B`9:BH9:B09:B9:B9:B8:B8:B8:Bp8:B@8:B7:B7:B7:B7:B7:Bh7:B87:B 7:B7:B6:B6:B6:B6:B6:Bx6:B`6:B06:B6:B6:B5:B5:B5:Bp5:B@5:B4:B4:BP4:B 4:B4:B3:B3:B3:Bx3:B03:B3:B2:B2:B2:B`2:BH2:B02:B2:B1:B1:B1:Bp1:B1:B0:B0:B0:B0:B0:B0:Bh0:BP0:B80:B/:B/:B/:Bx/:B0/:B.:B.:B.:B.:Bp.:BX.:B.:B-:B-:B-:B-:B-:Bh-:B8-:B -:B,:B,:B,:B`,:BH,:B0,:B+:B+:Bp+:BX+:B@+:B*:Bh*:B*:B):B):B):B):B):Bx):B`):B0):B):B(:B(:B(:B(:BX(:B((:B(:B':B':B':B':B':Bh':BP':B8':B ':B':B&:B&:B&:BH&:B0&:B&:B%:B%:B?:B:Bٯ:B:B:BQ:B:B:B:B:B!:B!:B:B:B!:B:B!:Bo:Bn:B荫:Bn:BH:Bn:Bh?:Bn:B0T:BH:B`:Bo:BV:B荫:Bt:B:Bn:B0T:Bo:BV:BH:B`:Bn:Bh?:B荫:Bt:Bn:B:BH:B荫:Bn:Bo:B:B:B:B:B:B :B᳎:Bٲ:B:B:B:B:BA:B:B荫:Bٯ:BH:B@:B:BXz:B(:B":BR:B:Bo:Bʩ:Bb:B(f:BK:BXw:Bp:B:BV:BP:Bp:B:Bn:Bϩ:B:Bs:B(I:BHx:B:BВ:B0T:B(:Bo:B`:Bn:Bxթ:Bƒ:B;:Ba:Bn:B :B :Bh?:Bؔ:Bc:B:BPЫ:BA:B:BA:Bᰎ:BI:B鮎:BA:B:BA:Bᰎ:BA:B:B!:B:B :BA:B@:BA:B:B:BH:B`:B:BA:Bn:B:B:BI:B:B :BA:Bѯ:B_:B:B:BXz:B(:B:B":BA:B@:B:B:B:BH:B#:B:B:B@:B:BH:Bp:B`:B:BP8:B8:BA:B:B荫:B(:B:B!:BH:BA:Bi:B:BA:Bi:Bn:Bh?:B :B!:Bn:B(I:B:Bo:BK:Bb:BA:By:B:BO:Bx:B@:BO:B:Bn:B0T:B:B_:B:BU:B+:B:Bo:BV:B`:BA:Bn:B⃎:Bܩ:B:BD:B:BpX:Bh?:B:B:B:B:BA:Bn:Ba:Bƒ:Bn:BPЫ:B荫:Bg:B:B`|:B(:BF:B:BH:Bt:B:B:B蓏:BA:B:B":B :BX:B:B':Bi:BO:B…:B…:B…:BA:B@:BB:B@:B:B:B*:B8l:BO:B:B:B:Bn:Bo:B荫:Bt:B/:B!:BA:Bi:BPЫ:B:B2:Bb:B:BŽ:B:B:B;ш:B):BI:BQ:BY:Ba:Bi:Bq:By:B:Bɇ:Bو:B:Bሎ:B鈎:B6:B:BpZ:B:B:B:B:B:B:B୩:BXz:B:Ba:Bo:B{:B}:B:B:B:B:Bq:Bɸ:BY:BѸ:Bq:Bٸ:B:B :B:BḎ:B:B Ȝ:Bܩ:B"I:Bn:B é:B۩:B"I:B_:B Hͩ:Bxǩ:B ѩ:Bȩ:B=I:B:B<I:B!:B"I:BH:B<I:B:B<I:BPЫ:B ``:B@:B I:BXz:B I:B:B I:Bo:B I:Bn:B"I:B荫:B :B :B*xB(*xBxBtB2XBBxB`hFxBj#xBPPBxB8#CxB(4DxB CxBzCxBtB6CxBCxBStBUtBXNBxBQFxB$xBtBCxB8BxBhtBExB|CxB xBPlCxBȔCxBJ xBtB(ԶtBHtBƶtBH}CxB)xBGxBBxBFxBDxB@CxB@~tBmCxBFxBBxBpsCxB BxB UtB`GExBGxBBxBCxB@CxBxACxBCxBxBXCxBCxBCxB0*xB CxBFxBpCxBADxB:B:BH:B:BX:BȜ:B:Bh:B:BH:B :Bx:BxϪ:B(:BH:B:B!:B :B8:Bb:B:B:Bx%:B0C:BE:Bt:B:B:Bͫ:BCxBCxB(CxBеExBCxBltBp)DxBxB xB4xBh $>$>%$>;$>I$>W$>G>U>c>e$>{$>q>> >>)>>>$>>>>>5>> >$> >> >$>>)>7>E>S>a>m>y>$>>U=>>>>c=>>>$> >$>$>>>+ >===$>%>%>%>+%>9%>1>;>G%>U%>c%>q%>%>%>G>S>a>9 >%>%>%>%>%>%>&>+&>A&>W&>m&>&>&>&>&>&>C>]>&>&>&>'>%'>;'>I'>_'>m'>{'>'>'>'>'>m>'>o>'>'>'>y>==O=> (>>]=>>>>>>>>>>s===(>======->C>Q>]>i>u>>>>>%(>>>>G >y=3(>==>!=>>= >>'>5>/===K>Y>g>K=u>A(>O(>] >k > >>> > >>>{>>>](> > > > > > > > >k(>+ >9 >G >U >=c >q > >Y=>y(>(>(>(>(>g=(>>(>(> >>(>(>> )>)>>>))>7)>E)>S)>a)>o)>})>)>)>)>)>)>)>)>)>>)> *>*>%*>3*>A*>O*>]*>k*>y*>*>= =>*>*>>#>7>E>Y> >>*>*>>> > >u== >>== > >>>=>>>= >>)=->9>G>S>_>k>w>>>>>>>= >;=M=*>>=*>>>*>>*> +>+>)+>>7+>>==>E+>!>/>S+>a+>o+>=>K>Y>g>s>==!=/=;=I=}+>W=m={========+>+>= =+>+>>+>> >_=+>+>+>,>,>,>+,>9,>G,>U,>c,>>>>>q,>=5=C=Q=g=}==,>=======> =='=5=C=Q=_=m={=====>>,>,>=q==>>+>======#=/=;=9>E>,>,>,>Y>g>s>,>=3 >E >==>>>>>a=>,>>>o=>->======,>;>I>_>k>w>->>>>>=->>W >)->>>i >>========>== ==3= >>+= > > > > > >%>3>=7->A>E->S->O>]>q->k>y>->>>>>== ==->>>>>>> > >) >7 >M >[ >i >w > >= > >->->->>->->-> > > > > >% >3 >E=A >->-> .>.> >O >'.>5.>C.>Q.>_.>m.>a >o >} >.>)=.>.>= > > > >.>.>.>.> > >.> > >>%>=3>A>O>]>===k> />/>'/>5/>C/>Q/>_/>m/>{/>>/>+>/>/>/>>/>/>>>>>>S=e===>>!>;>===U>k>y> =>>>!=>>>>>> >>)>7>E>7=E=S=a=7=[>i>o=w>}====9>O>]>/>/>==== 0>0>s>%0>30>A==A0>O0>]0>k0>>y0>>=%= >0>0>0>>>0>===3=>>0>>0>>0>0>0> 1>1>)1>71>E1>S1>>>>a1>>>E=o1>}1>1>1>>>>>== =='=O=>!>/>=>K>]>k>S=y>>>>>>i=>{===>>>>>!>/>=>K>Y>===o>=>>=1>===]=> >1> >>>>>s=>>>>#>1>1>)>1>7>E>?>S>=M>[>i>='=w>>>>9=>>>>>> >>5=C=Q=a>o>}>G=U=>===>=1>1>>!>>!>2>2>#!>1!>?!>M!>[!>i!>k===2>w!>!>!>-2>;2>!>I2>W2>!>!>!>!>e2>s2>2>!>!>->=>>9>2>2>2>E>2>[>i>>2>_=m=2>=======2>2>3>">3>#3>13>>>>>>>>> > >) >7 >E >_3>=S >a >">1">?">M">>[">i">w">#>">">1>C>=]>k>">">">">y>)=9=>{=!=/===K=m3>w >>==G=U=_=i=!=A=S=a={3>=">>=74> >$>3$>s$> >-=O= >$>>=e=>{=>>># >=+>q=%>=%>%>%> &>#&>9&>O&>e&>{&>&>&>U>&>'>'>3'>W'>'>'>k==== ==;>==U >>==C>y >= > >>(>===-=>*>= >/>Q>g>O=o>u>}>>c=w======>!===>===e======>> >/=+>=-=_=u==E==>==S=k=Q>>>>+ >I=Q=Y=>{=>=%>=W>,>!->>>=====G=_=w > >a->i->w=>===E > > > >={.>.>.> > >.>==>#>y>>>/>/>>>>3>=M> >c>=/=>S>=G>k>=1>=>>a==g>> >k=> >!>1>=>>>==c=>y===!>'>>2>S>u>}>>==>?3>G3>>O3>W3>!">)">U>">!=o >7=Y=>=5=m=s=">3>">#>3>3>#> #>#>3>=#>=3>>=##>g==G#>= =O#>==W#>%=]#>-=5=e#>k#>==E=M=G=o=y#> >w=!4>=> >=>===== >'4> >/4>==========> >>94>#>===U4> >4>= ==#>/=C=4>W=k=====4>===4>4>====9=O=g===== = ===A=W=m=====>#>E>[>q>>>>>/>G>i>>>4>>>>>>>>>>>>>->A>U>w>-=>>4>#>>>>>5>M>m>>>>>>>#>#>U= >#>== =>>=>>>]=>> >#>'>k=/>=s=#>#>#>#>#>4>%=#>#>7>?>#>{=====-=3=A========/=C==W=k====>>=G>W>g>w>9=q================ =='=-=3=9=C=I=S=Y=c={=================%=/=9=C=M=W=]=c=i=o=u================== ====%=+=1=7===I=O=U=[=a=g=m=s=y=================#=-=7=A=K=U=_=i=s=}================ ====!='=-=3===C=M=S=Y=_=e=k=u====================%=/=9=?=E=O=Y=_=e=k=q=w=}======================== ====%=1=7===C=I=O=U=[=a=g=m=s=y======================%=/=9=C=M=W=a=k=q={=================== ====%=+=1=7===C=I=O=U=[=a=g=m=s=y======================== ====!='=-=3=9=?=E=K=Q=W=]=c=i=o=u={======================== ====#=)=/=5=;=A=G=M=S=Y=_=e=k=q=w=}======================== ====%=+=1=7=A=K=U=[=a=g=m=s=y======================== ====1=7===C=I=O=U=[=a=g=q={=================%=/=9=C=M=W=a=k=u=============== ===)=3===G=Q=[=e=o=y=================#=-=7=A=K=U=_=i=s=}============== ==='=1=;=={====={===={=={====={==={=====3>Q={===={=#={====={=#====={======{=#={===={==={=={====3>m={==W={=={====={==={=3>{=={=={=={=k=={=k==={=k==={=k====={===+#>+#>+#>{==9#>={==9#>=9#>{=k=9#>{==9#>=={==={==={==={==========={==={==={=={====={==={====={======={==={==={==={==={==={===3>{==={=={==={====3>{==={==={=={===={=={===={==={==={==={===={=={=k={=={==={=={===={======{= ==={= ==={= ==={='=={= = ==3>3>3>3>3>3>3>3>3>3>{==={==={=={=={=k={==={=A====={===9#>{==9#>=9#>{=== 4>={== 4> 4>={==={===={==={==={==={=={=={====={==={==={==={=={=k={=={======{=={=====w==i========={===={===={========{=u=u={==={=={====={=={==={=u=u={={==={===={==={==={==={==={===={========%=={==={==={===={===A4>A4>A4>A4>A4>A4>3>=========A4>A4>A4>==A4>==]4>k4>=y4>4>=y4>4>=y4>4>=y4>4>=4>4>y4>4>===U=i=}={===U=i=}={======U=i=U====i====U==}==">=>=74>==[=_=e=">">">k=u={==>>==3>3>3>a=C=>s#>+== >O4>3> >+^\$jm9ohҫs_N^2,bb$2OOiHq,?^tYrG@<<>/\":;?*|,=`<>/\":;?*|,=` 8 8      :B:B0 :B:B0:BP:B           :B:B0 :B :B@:B`:B   :B:BA:B:B      :Bq:B0 H:Bx:B:B:B    ,((04 -  -   ) ) !!>    !!>  !!>  !!>!!>   !!> !!> 1 1       Ex A| -       :B@:B::B !@j:BX:B:B@:B;:B !j:B:B9:BP:B@;:B!@`k:BH:B9:B:BP;:B!@k:Bp:B9:B`:B`;:B!@0l:B:B9:B:Bp;:B!@l:B:B:B:BLM;:B m:B:BP:B%;:B q:B:B `:B;:Bs:B:B :B :B :B:BP:B@:B(:B@hh:B:B ȓ:B0 Ѝ:B@:B`:B:B:B :B:B :B:B:B ؕ:BH:B X:Bh:B:B :B:B :B:B:B88:B:B :B:B:B<:B0 :B:B8:BX:B:BȜ:B!:Bܩ:B:BCx:BH:B  X:B:B:BGȤ:B0 :BP:Bp:B:B:BHХ:B0 :B蚏:B:B(:B:BJ0:B0 H:B:B:B:B:BK:BX:B h:Bp:B:BL@:B:B :B:B:BN:B:B :B:B:BTp:B@:B P:B`:B:BV:B:B :B:B:Bé:B!p:B۩:B:B_:B:B :B:B:BHͩ:B!:Bxǩ:B:Bѩ:B!p:Bȩ:B:BvXީ:B:B  (:BP:B:B :BX :B h :Bx :B:BB:B :B  :B!:B:B``:B!Ȟ:B@:B:Bf:B`!:B:B@g:B:B:B!؟:B :B:B茪:B!:BX:B:BP:B ":B࢏:B:Bu :B4*  ":Bx:Ba:B:B 0#:B:B:Bm:B(, $:B:B:B:B$:B:B:B:B $:Bp:B:B@:B :B:B:B 78$:B:B:B'X:B %:B:B:Bz:B%:B8:B:B`:B:B:Bsؘ:B%:B:B:BX:B &:BÏ:B:B|ș:B&ŏ:B:Bn@:B P&:B(ɏ:B:Bx:B`&:B@ʏ:B:BwH:B 8&:Bʏ:B:B:B(ˏ:B:B @:B &:B Ώ:B:BȜ:B$&:BΏ:B:Bo:BPϏ:B:Bc:B &:Bя:B:Bqx:B !&:BXҏ:B:B؞:B ӏ:B:B:B @':BՏ:B:B :B `':B֏:B:B{:B p':Bp׏:B:B:B$ 'Hُ:B:B((:B (:Bڏ:B:Br:B (:Bۏ:B:B H:B (:B܏:B:B:B2(:B8ݏ:B:Bh:B0(:Bޏ:B:B:B Xޏ:B:BlH:B2 (:Bߏ:B:Bi:B4$0):Bߏ:B:B)x:B@):Bh:B:B.p:B P):BP:B:B+:BO&Sq):B:B:B*:BO&Rq):B:B:BŪ:B ):B8:B:BŪ:B0 :Bx:B:B:B:Bƪ:B0 :BH:Bh:B:B:BǪ:B0 :B :B@:B`:B:BȪ:B,/, *:B:B:Bʪ:B0*:B:B:BSx˪:B  0P*:B:B:B2P̪:B%.*:B:B:B3ͪ:B  9+:BP:B:Bͪ:B AP+:B:B:BBxϪ:BDO +:B :B:B7ڪ:B;B+:B:B:BU:B#H:B:BQ:B).:B`:B:BR(:BWQ[Pp.:B:B:BEH:BCC.:B:B:B1:B .:B :B:BO:B .:B :B:BF:BP^a.:Bp :B:Bh :B/:B:B:B% :B:;.J/:B :B:B4:B54.Jp0:Bx:B:BM@!:B  :B:B?!:B/. Q@01:B`:B:B9#:B @2:B:B:B:`$:B p2:B@:B:B;$:B2:B:B:BPx%:B 6I2:B:B:B/`':B 2:B:B:B':B2:Bp:B:B!8(:B3:B:B:B"(:B 3:B:B:B6 ):B03:B:B:B):BP3:B:B:B*:B\f`3:B :B:B:B6:B(!:B:B7:BQR7d3:B!:B:B0C:B+,($:B:BE:B04:BH$:B:BpF:B(%:B:BG:BQ2V 4:B%:B:B#8S:B0 &:B&:B':B0':B:B$@T:B0! P':B':B':B(:B:B&U:B./"C`04:B (:B:B,_:B A4:B*:B:B-`:B0 +:BH,:Bh,:B,:B:B0`a:B,:B:B5b:B0 ,:BX-:Bx-:B-:B:B=c:B0 -:B(.:BH.:Bh.:B:B>d:B0 .:B.:B/:B8/:B:B@ e:B0 X/:B/:B/:B0:B:BAf:BP5:B(0:B:BDf:B0 x0:B0:B1:B(1:B:BIg:B0 H1:B1:B1:B1:B:BWh:B  `5:B2:B:BXhi:B  2:B:BY0j:B  3:B:BZj:B  4:B:B[k:B  4:B:B\l:B  4:B:B]Pm:B  P5:B:B^n:B-p5:B5:B:B`n:B 5:B6:B:Bao:B 6:B07:B:B:Bbo:B7:B:Bd p:B;"P06:B8:B:Beq:B: C@6:B9:B:Bfxs:B<`::B:Bht:BP6:B ;:B:Bgu:B<`H<:B:Bjw:B+6:B<:B:Bkx:B=L=:B:Bpy:B 6:B=:B:B:BtXz:BP>:B:Byz:B6:B?:B:B}`{:B06:B(@:B:B~|:B$7:BA:B:B}:BgB:B :B~:B@C:B:BH:BC:B:B:BC:B:B:B  7:B@D:B:BH:BE:B:B:B8E:B:B:B @7:BhE:B:BH:BE:B:B؃:BPF:B:B8:BI:B:B؄:BhI:B:Bp:BI:B:B:BJ:B:B:BhJ:B:B8:BJ:B:Bȇ:BK:B:Bh:BhK:B:B:BK:B:B:BL:B:B@:BXL:B:B:BL:B:Bx:B M:B:B:BM:B:B:BN:B:B8:B`N:B:B荫:BP7:BN:B:B:Bp`7:BO:B :B:BO:B:Bx:B1 P:B:BБ:BhP:B:Bh:BP:B:B:B Q:B:B:BpQ:B:B(:BQ:B:B:B R:B:B:BgR:B :B:B@S:B:BP:BS:B:B藫:BS:B:B:BHT:B:B0:B p7:BT:B:Bș:B(U:B:B:B07:BU:B:B:BV:B:B0:BW:B:B:B07:BpW:B:B :B+7:BX:B:B:BH:B`Y:B:B`:BYV]p7:BZ:B:B:B./6BP8:B`[:B:B:B `8:Bh\:B:BH:B8:B ]:B:Bظ:B./!BX8:B`]:B:Bë:B./5B09:B`:B:Bͫ:B+,(`:B:BPЫ:B @P9:B(a:B:Bѫ:B9:Bb:B:Bѫ:B09:Bc:B:Bѫ:Bc:B:Bҫ:B 9:Bc:B:Bӫ:B./ FB9:Bxd:B::B ::B :Bݫ:B::B g:BP:B::B ::B ::B ::B :B@ޫ:B::B g:B`:B:Bޫ:B0 g:BXh:Bxh:Bh:B:B߫:B0 h:B(i:BHi:Bhi:B:B:B  i:B:B :B:B :B:B :B !:B ):Ba:B:B Ἆ:B:B鼎:B቎:B@@@@@@@@@@@@@            u     uu u                      q                                              u @ȓ:B{P:B pƪ:B5s 6 3 P:B 7 Z:B83,T:B :BC{I` :BpH:B p5n:B~s:B0s  :B s  я:B@!:B s%؏:BH:BȪ{% :BH:B!N:Bs:Bhs  :B8 s  :B :B~s:Bs  :B s  я:BF:B~s:Bxs  :BH s  я:B0鉎:Bods%Ꮞ:BPM:BHds%Ꮞ:B(M:Bpd s%Ꮞ:BM:Bds%Ꮞ:BL:B`d{%L:BȨoYVds%Ꮞ:BL:BШy s*%:BL:Bxy%s*%:BXL:By*s*%:B0L:B8y/s*%:BL:B@y4s*%:BK:B9q-% K:B`o>s-%ɏ:BK:B`Cs-%ɏ:BxK:BHHs-%ɏ:BPK:B0Ms-%ɏ:B(K:BRs-%ɏ:BK:BWs4%ُ:BJ:B\s4%ُ:BJ:BЦas4%ُ:BJ:Bfs4%ُ:B`J:Bks4%ُ:B8J:BHx:B~s:BXs  :B( s  я:B8:B~s:B s  :B  s  я:B :B{j:B pƪ:B0s p1 3 j:B 2 v:B 33,:B X:B~s:B s  :B  s  я:B :BqM:BDq M:BC qM:BCڪ:B{{> :BN:B 1[>s>8:BhN:B hȜ:B 3:B3:B3 :B 3:BȤ:Bs 3 r:B:B e:B  3,T:BХ:Bs 3 r:B:B e:B  3,T:B0:Bs h3 r:B:B e:B  3,T:B:B 3 3 :B :B  3,:Bé:B 3:B3:B3 :B 3:BHͩ:B 3:B3:B3 :B 3:Bѩ:B 3:B3:B3 :B 3:B:B 3 3 :B :B  3,:BA:B'3(3)3*3X+3``:B 3:B3:B3 :B 3:Bq:B  3 3 :B :B  3,:B:B 3:B3:B3 :B 3:B茪:BL{t x!{p `{!{t О{  { { { p { { О{ { p | {  }m  { @~T  ${8 ؝ـI  ({t ȝ@  ,{ 8  0{ I& 4{X ) 8{ <{ x@{ hYD{ XH{ HyL1p P:B{X s{ I;tY) ;p  ;  :B:BZ;&@P;'`@;(@`;)d@;*@ ;+@ ;,x@ ;-@!;"@ ";#@#;.@0$;/h@%;$@A-&;%l@ɘ';0$`@( ;1@)";2*$;3\+';,*;--;4.0;4 /3;5 06;6t 19;7l2<;8D03>;9 4@;:l 5C;;D ɹ6F;< 7I;=8 i8L;> A9O;? :R;@;T;A q<W;BX 9=Z;C a>];D?`;E4A@c;FAf;GqvBi;H\ nCl3I`u:BDp;JHgEs;KyFv;LeGy;MH{;ND I~;OQJ;PI K;QHL;RM;S qN;T O;UP;VlQ;WR;XS;YHT;Z<U;[V;\XYW;]4 X;^ |Y;_4vZ;`h[;a\;b 97];c 2^;dp 9_;eTQQ`;f;a;gX&b;hc;i d;j81e;kYf;lpg;mL]h;n!Ei;oX j;pak;q)l;r QPm;s5n;to;u )p;v8q;w@ )r;xp! s;yɨ :B t;z`Qu;{(v;|4 Iww;} x ;~ y ;(z;({;( 1o|;@Q}; 15~;( ɔ :B){ IN*; >+{ Q0, { hq-{ P.{  @ /{ x 0A 0{ \ :B#;p { `9{ Еi { `y{\ 9Y{ Y0{ , p{  { @#{ '{@ +{ p9/{x 3{ '7{ y);{T y*?{p *C{ ,G{ ؓ K{t ȓ! O{  #S{ -=Wq|.Yq.[q.]{h.\a{ X).e{@H,i{ 8%m{!t (9#q{"4 yu{#|y{$ 9}{% \{&` ؒ9+{' Ȓ:B& { ؒ? {8  ;t!{  :I" { X6#{ h 5${ 5%{  5P&{ )-0' { T Б-L($;p ?:B;@?;@XD;D(D;L @+ { `@ { <X@S; xD@:B {t 8QD{ E;)E ; D:B2r{ Qs{  Rt{ 8yRu q Rv{ H xRw{ t 8Rfx{ H)UWy{ 9WJz{D IZD{"{d[6|&{x Y[}*{x H^~.{ Ic 2{( HIK6{t d:{ ؏e>{ XgB{ iF{<(kJ{dhIl~N{ ljR{( 8o[V{ )qKZ{ yuG^{ iv7b{ z-f{ i}j{!Ѝy~ n{"Ibr{#Dv{$XHz{%0~ ~{& L{'8pG{(@ `Eb{)4 PD6{*@)C{+0)K+{,, IB{-A{. @l{/|J{09@#q1 Bq2Bq3TCq4HBq5Bq6pB1 1p X:B-;p}.;t ~/{ I~p0{ |G1 { Y|#2; }:B% q { t ,{  { 9{ 4xy{ 8)~Z; };Ɉ;u;`Ɉ]"{XɈ$`:B{'!:Bpƪ:B{':Bpƪ:B{':Bpƪ:B(H{':Bpƪ:B{' :Bpƪ:BȊH#{':Bpƪ:Bh*{':Bpƪ:B@1{':Bpƪ:B08{':Bpƪ:BV?{l э WC{t ؉Q XGs P:B:Bw:B7:BP0:BYPs B:B:Bw:B7:BP0:BZYs( 6:B:Bw:B7:BPh:B`[bs *:B:Bw:B7:BPh:B\ks :B:Bw:Bp7:Bp0:B]ts p :B:Bw:B`7:B0:BX^}s :B:Bw:BP7:Bp:B_s D ٗ:Bꗪ:Bxw:B@7:Bp:B`s, Ǘ:Bҗ:Bpw:B07:BPP:BPas )̪:B:Bhw:B7:BP:BbsD :B:B`w:B 7:Bp༏:Bcs :B:BXw:B7:BP:BHds4 :B:BPw:B7:Bpӏ:Bؘ:B% q 0 ;  { q  q ,  { @ { { hm{ Xo;ia;x aU!{x 8QA%1p X:B3;p V; {   q  {t؄{ y{ `{ Pq q Е q@"qt0${Hٔ({i,{ 0{LЃș:Bm!q q @{ YF{ Y; { Xɪ%{ l Iq { Yq  0q  pq  q "q $q &q `(q *q Ю,qP `.{p 2{ HH6{X xɢ:{H yi>{$ (>B{ ٟF{ J{ p)N{ `Y:R{ PYQV{  @9Z{! 0y^{" b{# =f{$ Ij{%| @:B{Ȁɬ{Ȁq8  {|{ < P{ (@){ 009{ T I1 :B{ qXqH:B ; ٵ{ Y{(hX { ``:BZLq Mq Nq @O{ XP { ~YQ{ T XRq Sq T{ t ~QU{ ~V{ x~ W"{T ~iX&{ H~Y*{H X~YZ.{ }[2{ }E\6{ }]:{ }^>{ })_B{T p})`F{ `}gaJ{ P}i:bN{ @} cR{ 0} dV{ }ٲeZ1 @:B=q >q(?q@qAqHxB q HC q Dq hȜ:B h;p i{@0|9j{|^k ; AL:BC{| {0{ |1{| { {| {{ {Q{ {/{ H X{Q{ x{ { | z${ | za({| z,{| z!0{| zq4{| zas8{| z?<{| pzq@{| `z:Bo{d @zAp{ zqq{X yAr q s{ , yat1 uq x:B{ yy-{ xy|q qh` q|q q ؞:BY {'D:Bpƪ:By{';:B pƪ:Bxg{'7:Bpƪ:Bx{'3:Bpƪ:BXx{'):B pƪ:B0x$s k:B:Bw:B8:Bpӏ:Bx-s R:B^:Bw:B7:Bpӏ:Bhw6s 8:B^:Bw:B7:Bpӏ:Bw?sX :B:Bw:B 8:Bp`ӏ:BHwHsp w:B:Bw:B8:Bp(ӏ:BvQs X D:B:Bw:B7:Bpԏ:Bv:Bq ` q@q@q{ Xv { @vrq |  :Bl{t v [m{t u ,n{X u io { ui Ip{ X u q1p :B@;p { `u{ @Huyv qp  q @{  8uy9{  ty"{ ( u{ t{ pt #{( `ti#'{l Pt &+{ @ty./{ 0t.3{< t/7{ t;q ={D s :B {% s2*{& s0;$ a2$(:B3 3; <)4{ s85{Hsi8=6 {4hs;7{ x s8n8{ s:c9q ::{ r::;{ r: <!{tr; =%{TprI7>){ `rI4{?-{Pr 2Q@1;3=:B; Y?{r={rI?} { qI?6{ qy={ q >;a?;x>H:B9q?:q0?;q@?<q >:BE{q?F{dq`?G{(p?H {p>I {\p>J{ p`?K; q?h:Bf{ ppQ?pg{Xpp?:B{ @pYA4{ pA{ o? { oI@1 H:B { oC;@C;@hB;DCt ;LAL:B6;@xF;@E; E${ 8oIE { hoD{oxH{ oC{$nC{ |nCZ{!<pnB {"hnB#; C$&; @ F);D0F+;L 1F.{#HnG1;E4;Gx:B8A{0nSB{ xnOC{ mXND {nME;aMgF;MJG;,L+H;yL I;<LJ; JK ; JL"; `JM${ mIN'{ mqIcO+{mI;P/{ lGQ3; @HGR5; l@FS7; xFp:B o1 pq` TqqSrqSsq\`pRt q `Q:BY;O!a]Z{PHl][{Q lXr\ {R lS-];M)]^^;NQV:BT;O!)bU{Pk` V{Q k\W ;M`X;NQ`Ū:Bq8`bq<bqaqHaq Da q 8d { x j dR{ x ja"1 Ū:B{'O:Bpƪ:Bjds xj 3 J:B :B Z:B 3,T:Bƪ:B{'n:Bpƪ:Bic1s i2 3 r:B:B3 e:B 43,T:BǪ:B{':B pƪ:BiIc*s `i 3 :B:B u:B3,T:BȪ:B{-hc{.Xhc;, )cQʪ:B6{ hh1{ hi3{ h e {0 hhc{ hhb{ < hf{ gYfW{ | g e[ q  @k"{ gj&q pj(q 0j*{ gyi.{ g)i2{ pg)d61 x˪:BEq ,xqwqwqhwq w ; u qt{ fIs{gYrT{Dfq(; p1; o"; m%; 41m(; l}+; !lb.{eqk: 2{Hej 6{,ej :{eAj >{eAv& B{ ehP̪:B"{':Bpƪ:B f0{':Bpƪ:BHes X ̪:B:Bw:B08:BP0:Bds )̪:B:Bw:B@8:Bph:Bd { e$;I'q)q+q-q`/q01; a4{ d8{PdQ<{c@;YgC1D{cAKH3I; L; ~O{ cI~S{c ~xW{c}}[{ bIzG_{4b9wc{bisg{ bsk{bY=o{ `bis{! buTw{"b){{#t pbv1; 4 qx{q$xͪ:B0q ,qq ; ` {a ; !{Da!1; ; ; 4 юe; L!{ HaɌ%{H8a)){, (aY_-{ aͪ:B@q ; x; ٚl;pQI ;<3{ `){`){ p`ٕ{ `ْm{ _"; q%; (qP*{D_R.1/; i>2{ _,6{< _,:{_9>; AxϪ:BZi{;!X_Pj{<9_k{=8_l {>)_m ;5vn;0a fo;/p{?q `_Yq{@^iZr{A^ s!{B}^ t%{Ce^ u){D5^ v-{Ee] cw1{FE] Cx5{G-]#y9{H]z={I]{A{J)]*|E;6 Q}H;.9~K{K]ɴO{Lx])S{Mh]W{NX]9ڪ:B(:BB{':Bpƪ:B0]s?9 ڪ:B:Bw:B8:BP8:B\s@Y ̪:B:Bx:Bp8:BP0:B\;;!y{A! \ٶ {B X]#{CeX\&3.'{DH\*{Ea]ص-{F(\0{G]3{H\6{I\9{J[={K[A{L[D{Me[G;/I{N[bM{O \AQ{P `[U{Q `\}Y{R0[o];0a(`;19Mc;25f;3Yq(i{S`[l{T Zip{U [yt{V! ZYx;4}{{WEpZ{X!PYP{YIHYz{Z 8Ya{[(Yi;5 q7{\) Yq${] Y3y:B{^ X3{_9X{`Y X{ae Xj{bexX{c hX7{d%XXa${eAHX {fA8X{g(X{h X{iXa {jYWAR {k W% {l W {m W {nMW{oUW`{p=W8{qWq36 {rMW{s Vڪ:B?{t W]{uU W2{v@W {w5V{xu W{yiVy{{zV P;7 ѽ {{u 8V #{|y Vq'{}]V+{~=`V .{A@U!1{}`U"4{@U#7;8$:;9QA%=;: :B~sX ̪:B:Bx:B8:BP0:BpU q  { hU {p U { 8U1!{ L U!{ , U!{ HUQ"#{ T#'{ L 8UA+{L T/{L TA3{ xT7{0 Tq;{ HTB?{ hTQC{ SG{H S! K{d S|!O{ pS!K"S{ `S #W{ PS $[{ @S %_{ 0S1 &c{ S r'g{ S!4(k{ S)o{ R*s{ \ R+w{!` Rh,{{" R :B, qH!{ RA!{ hR!` { R!W1L;` #A1@{ 4 R&.{ ,R) {QI*s k:B:Bx:B8:Bpӏ:B`Q({ QA*,1p (:BsX9 ڪ:B:Bx:B8:BP8:B(Q ;W!i/E {Y!Qi/,{Z Q/H:B* {;!PH;{<9Pp;{=Px; {>)P; ;5;;0a !2v;/4;6 4l;.7o{?(P!8Y{@mP8G#{AP!92'{BO9:B ~q=q <1L{ 4O; ;`;:Bq<q<{ PO<-{$ O=M {O<&q x<{ N>:B+{':Bpƪ:BN>s; :B:B x:B8:BP :BHN{N;/?F{= N@6{>yNF6{?N)G #{@M)G'{AuXNYq%+{BMq/{CNq3{DMq7{E-Mp;{F]XM)pu?{GMoOC{H9(MYo#G{IxMnK;5jN;3YIjQ{J LhdU{K Mh8Y;0a a`\{LMK_`;4} I\c;6 1Wff;7 Vi;.QU(l{M)KTp{NKQTt{OKSx{PKS|{QxKaRg{RhK!R{S XKAD{Ta HKj{U-8KZ{V0KZ{W(KPZ{X K9{YK`U{ZKT={[eKTz{\ JXT{]yJp9h :Bq 0n;` An :BF;:q i{;;!|{]PJ|{?pJ|{@1 J|_ {APJ}F {Be IQ}-  {CJ~ ${D= hI (;QɁ+;-A.;D91{Ey @Iɂ5;i8;\ك;{F I>{GIA{H@ID{I%@I :BP{6H){7HII{8MHg {9%HɆN{:H{;AH {<hH({=eH0{>HH9 {?mxHi$${@H؇'{AG*{B`G-{C@G0;\ Q3{DG7{ExGQ;{F hGъx?{G) XGnC{H HGZG{II8GQK;4!GN;5q 6@!:B#3%y:B{ F{ FA {T F{T xF{ pF!{ `Fє{ p PF1 { 0 FA$!:B$<{0XFA!={1xF>{2hE1&? {3Fѥ@{4 EQA{5FB{6xEaC{7dFGD {8HE]E${9E!F({:EG,{;EAH0{<DI4{=(EaJ8{>DaK<{?<EGL@{@PD!MD{ATDNH{BC1OL{CCўPP{D$CQQT{E CRX{FtCaS\{GpCGT`{H,`C!Ud{IPC Vh{J@CAWl{K0CѕXp{L CYs{M,CXZv;. [y{N Cyo\};1]{O@`B^{P@B_;\*`;/p Q#:B&q 'q(q8)q,H`$:B*q x+q$Ȣ,qx$:B-q Ȣ.q/qȢx%:B{.A{/4A{0PA {1 hA {2H PA{3 @AI{4l 0AT{5$ A&`':B u1 v{ @ѨHwq@ ȧxq y { @':Bq q 1 ;p 8(:Bq(ȩq1 (:Bq$@q$Щqhqx1 ):Bq 8qqة):Bq (q*:B {_@0?{`@>h{au@>` {ba@> {c@>`{d!@>{e! x>a;[1Y;]v;^iY^6:B {:Bpƪ:BpX3H!:B7:BF;Qq {S >1{T = {U}= {V`=l{W%=V;R! E{XeH=C{YA =), {Z<${[A<;({\ <I,{]p</{^h<Q3{_X<7{` H<1d;{a8<Ѵ?{by(<Q՝C{cu<0C:B;+ E:B;p q;8λ{; {p;9{T`;Y{P;; 9tpF:B ;@Q6;B{p : ; G:B{R:{S:;DAȺ ;(i {T=x:y{Uh:[;Q!!a8S:B{':Bpƪ:B@: s (: 3 :B&:B :B 3,T:B@T:B{':Bpƪ:B9s p9 3 :Bp':B :B 3,T:BU:BT;.q {0 9y{1 H9Ǵ ;Q Ao{2P9aj{38v{4=8O{5e8A6{6)8 "{7=`8A!&{87ϳ"*{9 7A#.{:-7$2{;7qv%6{<7O&:{=7!6'>{>i7(B{?1x7l)F{@Uh7L*J{AX7!T+N{BiH7+,R;/!I _:B _q `{ 7i(aq bqc qd q Xeq fq pgq l@hq hiqjq8`:B{' :Bpƪ:B68ks 5l 3 :B+:Bm :B n3,T:B`a:Bz3`{1L|1@}1 b:B{'.:Bpƪ:B5s p5 3 ':B-:B :B 3,T:Bc:B{'<:Bpƪ:B4x4s 45 3 J:B-:B6 Q:B 73,T:Bd:B{'k:Bpƪ:Bx48s `49 3 y:B.:B: ^:B ;3,T:B e:B{':Bpƪ:B3as 3b 3 :Bx/:Bc :B d3,T:Bf:Beq( fq@g1 h1p f:B{':Bpƪ:B3xs 3 3 :B0:B :B3,T:Bg:B{':Bpƪ:B`2s H2 3 :Bh1:B :B 3,T:Bh:B-;@`.;/;0;P1;2 ; Q3 { 1 4{ 15; hi:B6{ 1@7{ | 18; 9;: ; ; ; P<;P 0j:B ={ 1Y>{ 1?; r@ ; @A ; j:B B{ 0(C; D;yE; F ; G ;P k:BH; 0I;Avl:BJ; K;HL;M;PPm:BN; O;P;Q;Pxn:BR1 Sq TqTUqVqW q X q Y q Zq p0[q `@\q|P]q`^q|p_qp`q4aqn:Bb1 cqdqeqfq<o:B g1 hq4iqjqkql q Xo:B{:B pƪ:B@x{:B pƪ:Bm37:Bn38:B p:B v; بw{,Qx{ ,ay { ,_z{!| P,1G{;Dy|;@};@ ~;@;LQq:B;p Y{ ,Y{\ ,( { +; Q{+@{D+I{L x+Ixs:B; { 8+!t:B ;@;@h;D;L  { *{ 8*a{ *{ ,*"{ tx*{ 4h*yu:B; ޥ{h(*ow:B{*P{T*p{) {)b;  );p a;8 ;d; 1x:B; yäy:B q\{L)I@q|Pq` 1 Xz:B#{:Bpƪ:Ba3p>:B3p>:B3 p>:B3` p>:Bz:B{@ '{@ X'1x{@ @'a ;p `{:B- ;@;@ {` 'D{ ' {&Y{&ϡ{h&{X&I{H&x {8&yO${(&y8(; Q+;p Y|:B{&i{%i~{%w {\%>{@ p%Il{ `%IL; A;p I#}:B ;  {\ %ߟ{ $aş~:B;@;; (H:B;@IR;; :B;@;(; H:B{H${ 4 $x{ 8($ { # ;h;@(;yP; @H:B; P:B; @:B {p#{h#;@ ; qn ; H:B;@6;"; ؃:BSA{ "!B{ #a}~C{ "aD { #E{( x"azF{ "bG{ H"JH{ x"2I { "J${ , ("K({ !!L,{H !AқM0{X p!aN4{, `!O8{ P!P<{ @!rQ@{ 0!ZRD{ !BSH{ !!*TL{ ! $UP{4 a 8:B;@X ;Y Κ; ؄:B;@ ; ; H p:B;@H ;I 9; ` :B;@ @ ;p; @:B;@ ;8 ; 8:B ;@IZ ; ; ȇ:B;@;; h:B;@;; :B;@;W; :B;; @:B;@ ܗ;; X:B;@ ;p; Px:B;@^ {( @G!;" { )# ; :B$;@Y%;xt&; :B';@(;A); 8:B*;@y>+; ,; @荫:B-q, .q 0 /1 :B 0; i!1{L  2{3 {!:B 4;@!,5;i!6{ P "7 ; !x:B8;l"9;0":; Y"Б:B;;@"<;A#R=; X$h:B>;@$?; !$@; x$:BA;@$B;$C; $:BD;@%E;$F; $(:BG;@X&H; $I; &:BJ;@P'K;Q'L{x 'ϒM {4 %N ; x':B O;l(~P{P)wQ{,8)LR ; (-:BS;@ )T;)U; )P:BV;@ *ɑW;X,X; x,藫:BY;@ ,Z;P,[; .:B\;@ 1.:];-^; -0:B _;@/`;/a{/b{/c ; @/ș:Bd;@0e; 0nf; 3:B# g{0 3<h{ 6i{2wj {(P2vwk{83owl{36wm;@3Mkn;45ko; 4[p!;p Q4M:Bq;@6r;)6s; 060:Bt;@8u; 6Ďv; 7:B$ w;@7x;@H8y{\08z{88u{ {9u|{;u}{8:Nu~{l 9:{ :э; ;t";p 8 :B; <{@P;{  ;: {H; {Q; H:B"{r:Bpƪ:BP;3xY:B3Y:B3pY:B3<Y:B`:B;Y! <{Z<pj{[hq? {\P>s;W>d;XQ ::B;.q AV{0 9Bj{1? {29@ۊ{3@Ɗ{4@{5 @;/!?:B;p QCZ{ PqAp{ Bp { Bp{0 AvpH:BqP D1 1p ظ:BO;.q Pʼn{0- hP;/!iO{ {1Q JC ;-!J{2ipI?{3 aI&{4PH~{5H~ {6!H~${7hG~({8XQD~,{9HFf~0{:8C?~4{;M(QD&~8{<D}<{=D}@{>IE}D{?!E}H{@yAE-L{A9Fë:B;.q V];/!T,{0YT| {1H!U| {2M8AU| {3i(qU| {4 Uͫ:B;+ W8PЫ:B/ ; X Ajv9?{? ahv:C{@x hv;G{AUh kvv<K{BX lOv=O{CH k6v>S{DY8 kv?W{E( 1ju@[;/!iƀݫ:Beq l@ޫ:Bfq kޫ:B{':Bpƪ:Bp kgs X h 3 :Bh:Bi :B j3,:B߫:B{'":Bpƪ:B kks  l 3 :Bh:Bm :B n3,:B:B o;0jp;jq;<kr;Qkh~s ;Plt ; 9lD~@:B V1 W1X1,Y1Z1[7[; m}\ 7\ ; 1n}] 78]; 8m}^; < l}_1 @:B }1 ~7~1 71 1 71 7< 1< 7 1P:B + o| ;,!o| + )o|:B + Qoy| ;,na| + oI|`:B +  o| ;,o{ + o{:B + ao{ ;,n{ + oy{:BH4; IZ{51 6; s>{71!8;"xyr{9 1: 1@; 1<1d=1>1 D?1 @1 A1#\ B;$< pzC1 D; pzE;przF;4q]zG!;%pAqHzH$;&Iq3zI';'AYzJ*;(EzK-;)-zL01M11N2;<zO53*P91+,Q:1 R;1,,S<1,T=;-~yU@;.)yVC1/WD;0xقyXG;1qdyYJ;2yLyZM13[N14|\O;5-y]R;6Ʉy^U17 _V18`W;9xaZ;xb];lQxc`;:xdc1ed;)$xfg1;gh1<hi;X zxil;$Iz-xjo;= Ax xkr;> xwlu;?wwmx;@vwn{;,vwo~;X)vwp1A8 q1 r1B s;C\ysSwt1D\u;Er0wv;Frww1Gx;Hqvy1Iz;J0pv{1Kl|;Lp ApvP:B< 1 ;!v;!Ɏv;v ;,yv ;qv;َyv1"`1 ; Ev1 t1 1 1T11x;lYu!1";Du%; u(1@)1d*;u-1.14/101#\ 1;<Eu4;'u71$81X910:;$< )t`:B1 1 :B CsI`:BHH:B CsI`:B H:B @!:B s%؏:BH:B s%؏:BxH:B 鉎:B'ds%Ꮞ:BJ:B ds%Ꮞ:BI:B y s*%:BI:B ys*%:BI:B Ps-%ɏ:BpI:B 0s-%ɏ:BHI:B s4%ُ:B I:B #s4%ُ:BH:B ڪ:Bs=:B@N:B s=:BN:B  s=:BM:B s>8:BM:B s>8:BM:B 7:B7:B 7:B7:B07:B@7:B`7:Bp7:B7:B7:B7:B7:BP7:B 8:B7:B7:B7:B8:B8:B08:B@8:B8:Bp8:B8:B8:B8:B8:B!I)A a  11 q 1 I q a I91QIa)qQi!q111H0P(HP`0^_klzxP{|]x]0@Xh[H2PK0@]HW`XXUș80H&P3``(T1XXhx8x8h@Т@`x@Hx`ȬHhhPPȵ`(P8Ƚ>HhHhH`Ph:8(pWX@0qXHxPh`  8880H`x 8Ph(@H0H`(@X0Ȼػx x 08@H`x0H`x 88 P ((0H`x 8Ph(@Xp0H`x(8Ph 8Ph@IHIpIIIIIIIIIJpJJJJJK K8KHK`KxKKKKKKLL0LHLLLLLM M0MHLXMhMxMMMMMMMN(NFFFFFFFFPN`NxNNOO(O@Ox88888889909H9`9p999999999NNNO O8OPOhOOOOOOOP(P@PXPpPPPP 8Php(8HXhxX h hxXO`OxOOOOOOOOOO P0PHP`P@@HPX`AAAAA@P@P@P@P-----Phx  0@Xp0H`p 0@Xp@5X5p555555556 606@6P6`6x66666670N@NXNpNp@x@@(h 0@Ph 0@P`p 8H`x 8Ph(@Xp 8Ph  0 @ P : :(:0:X:`:h::::ȴشKKKKhLxLLL45505H5`5x5555556 686P6h66666667(7@7X7p7777777788KLL0LhLpLxLxL@P`p(@Xp 8LL0LHL##$$($8$H$P$`$p$$$$x&&&&&'('@'X'p''''''((((8(P(h(x((((((())0)H)`)x))))))))* *г0HJJJJ`p/0/H/`/x/////P#X#`#x####X5h5x555555(@ px(8HXp@0H`x 8Ph(H H(H0H8H@HPH`HpHHHHHHHHI I0I@IHIpIIIIIIIIJJJ JHJPJXJ`JJJJJJJJJJJJJJJJJ K K(K0K8K`K`KhKpKxKKLHL`LpLLLLLLLLL(M8MPMhMMMMMMN`OpO(N0N8NHNXNpNNNNNHPXh(0@P`NNNOO(O8OHOPOO`pп0H`x 8Phpx(@Xp 8Ph(@XpMMMMM (08@0@Xp(@P`xPMMMM (08@HPX`hpxв 08@P`pȳس(@P`pxȴش(8HXhxȵص 0@P`pж P`hxȷط 8HJJJKPXp0@Xpx(@Xp 8@X`hpx 8PhHIPIXIpIIIIIIJJ0J@JpJJJJJJKK@KPKhKKKKKKKL(L0LXLhLxLLLLLLLM0M@MPMXMhMMMMPPPPPPQ Q0QXQ`QhQQQQQQQRR RHRXR`RRRRRRRSS8SHSPSxSSSSSSST0T@TPTxTTTTTTTTU UPU`UpUUUUUUVV8VHVXVVVVVVVVVW0W8WHW`WxWWWWWX X(XPX`XhXXXXXXXYY(Y8YHYpYxYYYYYYZ(Z@ZPZ`ZpZZZZZZZ [([0[@[X[p[[[[[[\ \0\H\X\\\]H] 0@Xp 8P\] ]8]P]`]]]]]]^^(^X^h^^^^ (0H` 80@Php 8HPXXȣأȴ008@HPh ](](]H]X]h]x]]]]]]^^0^H^`^x^^^^^^_@_P_`_x____0`@`X`p````````aa0a_aaabbb b@bXb`bxbb`abbbbbc c8cPchcccccccd(d@dXdpddddCCCCD(D@DXDpDDDDDDEE0EHE`ExEE8Ph(h(h(hccPd`dxddee(e@exeeeeee (08@HP`#h#(!0!8!@!(#0#8#0!!(08@@HPX`hp$$$ -(-0-8--8-@-H-P-X-`--p--H,P,X, )x))) )()0)8)P-X-`-h-p-x-,,-X      !" "("!!!,---- -(-0-8-P!8!P!**X&`&8"@"H"P"X"`"h"p""p"x"""P(X(`(''''''''' *(*""""""""""""""#### #(#0#8#@#H#P#X#`#h#p#x######'''''''&&&&&&&&&&&'''&&&*h p "$0#8#@#H#P#X#`#h#p#x#####(Xp0"8"@"H"&&!H!P!X!`!h!p!!X`8h( (((0(8(@(H(P(H@(H(P(X(`(`(h(p(x(((p(x( (( (HPX`h8 (08@HPX`hpxHX08&x (08@HPX`(&0&8&@&H&P&X&h8&@&H&P&X&`&h&p&x&&x0(&0&8&@&H&P&X&`&h& p&0&8&@&H&P&X&`&h&%%(&0&8&@&H&P&h&p&x&@&x&&&&&&&&&&&&&&&&&P X z0zXzzz7:B Ū:B!)ș:B(-:B:B3s':Bp,:B3l)`$:B:(:B=/C:BIBh:BL\]:B:BR05ͪ:Bp,:BRdu#:BTH8:BcL]H:Bs$I:Bv=`{:BwJ@:By<0:BzLҧX:BP(:B}Dl@:B؞:B:B:B0:B ƪ:B0C:B:Bu{ e:B(w:BP(:BKХ:Bܬ5x%:B@:Bl"!:BȤf:B :B+:B ,Ǫ:B:B(,:BѸcȇ:Bxf:B,:B:B7 :Bp:B؈|@ޫ:Bd#8(:BL:BhJB:BFѫ:BBl:B:BA>؃:B :B P:ByxH:BC0:Bo:BP(:B+`g:B.}~ͪ:B:B2] ):B3Q9:B4 s6:B56n:Bp:B6߫:B8ݓ:B:Su:B;i(:B@}z:BIW:BKm:Bp,:BMY_c:BS-`':BTepYt:BU}荫:BX5:B^]eh :B_e2@:Bg:BmE:Bpp:B~/@藫:BIf:BH:B#}:B0:B:BUx:Bp:BXީ:B0:BI?ȓ:B:B :Bp,:BHq8:BXz:B-r:B1x˪:Bp,:B-Hd:BH:BEe`:BcxϪ:BQ :B`؄:B#:BAŪ:BȭBJX:B9?>n:BىTj:B :Bۍ ؘ:Bu&IP̪:B:Buwx:Bq :Bΐh:B p:BP!:B&8:Be0j:Bx:B"&O:B&:z:B/$`:B1~=x:B8DH:BB!H:BM:H:BN{k:BQR@:BU{(:BZvx:B[j :B\Ey:B^G:Bp#:Bd ѫ:Bdv:Bqi;茪:Bsjg`:Bt&ѥ:Bp,:Bv$:BwP:BF@!:BI:BK*:BM7xs:B.Uظ:B`ͫ:B%:B:B0%:B`a:BN.:B~Ip:BzT6:BFz5}:B2.P:B*= :Bp:Bz ݫ:B.&V:B6ӫ:Bh:BF7ș:B:B&:Bҫ:BEѫ:B |:B0':B}:B&~:BVS:BHy:BbKo:B":B#Vq:B:BW:B@:BC7:B!?! :B#'Ȝ:B3u{ؕ:B8 U:B??@@AABBCCDDEEFFGGHIJKKLLMNOOPQRSTUVWXXYYZZ[[\\]]^^__``aabbccddeefghhiijjkkllmmnopqrssttuuvvwwxxyyzz{{||}}~~:B*:B*:B*:B*:BC*AP     PPPdA" ;i 1O3~  3~ 13~  """;A(X:  X X <<<E  GGGyAr F F  rrrA2^r^ ^^ ^ ^ rrr 222PAH r AUAw AAw   A  Aw   )  rrr +++KA(A(A(A(A(A(A(A(A(A(A(r}A(A(A(A(Ah/]     A(-A0;   ;  ^ \ \ C \    ;;;V   & 000PAm]2 222Y A(5 1AH7h hhhALd" L """: A--[ -- [[[z O A<( *   AH= AKBrr R N [N r KKKT [[[v  <  BBBl A(AHn AhAQ Ab(.|(h |||  bbbuAH 7   #AH 7   #A(kF="  F F """2  kkkA r  rrr   EAKV0 000H KKKkAQP0 0  AH( A(Qw 1Al$$T $$T  pppy  {{{Ahz*  Ahk A(8AH_S AZ2b? bbb 222YArp rrrA(/DAHW" H """: A( :1A": <h j <hj A(hAH+AAh3 A(|A(r~A(B1Av4J" Jn1'pJJn1    AHJ: A&k%aa  kkkAH8^ Alb    bbbr ?Av6b,;, v, ;;;b bbb AH:"L """:ABBr BBr  AH{D {{{Ac2l+ +++C 222YAq2~R RRRj 222YAH,{ A<c! 5 <<<LAH. 7AHU )AHl/ AhK%%a [a8rQ Q  Q   Q %a %a %aQ %%a % % %Q a a aQ ttt}   ```i  PPPY 2    J  kkk [[[~AH? AH? AH? AH&k kkkAH? AH7{ABBr BBr  AHmJ AH#[ A(PA$wGw '{ JJ  J w  wJ JJ  {{{    AhL  AH5? AhO AHp AHB AH;= ;;;DAHo>v AHc2< 222YAH. AHL  LLL\AbAA   bbbrAh;gBti tttAH]; AH= AHE- AH`Cq CCCYAHK KKKcA6{-  {{{A(#A(#A L dbd8|1d1 dd d1   d  d 1 bbbz 4 A+d     +++4A ]J]1]]1 Ahw2''f bfBOlO} f 'f ' 'ff 'f     BBBU bbb 222PACzR RRRj A,YH  ,,,@AHM A(D1A)Ge1+g Geg +++<A()BA(vA(A(vA(A(r~A(|Ah& A A(lzA(vA{D\k7 7 pppy FFFO {{{ QQQiAc -3 JJ_ J JJ J   J  J     333V 1AEzX: z <<<P RRRj EEE`A(bAhD A(AH. A(A(A(O`A(^yA(A%b' b '''@AHr rrrA(A(p|A(&2>bA(p|AHN A($!KA($A(#AH@ @@@PA(7AH3 333FA(A( pbb bb b b   pppA/]/e7e/ee //e/e A(A( A0cJ5cL7o 57o5 7o LLL` 000HA(]AH*Ue*UAH3 A(;ZyAhR`Gu RRRyAHw" """2A(sA  i N N i i i AS  vvd2d4}[  }[ U}` W6 ) vv S v S v v v 24 W)  W  ) UW U) b b b k   p p p  1 A(A(A(p|A(p|A(p|A(AH> AH 9 A(A(8WsA(lzA(vA(|bA($A(}CA(A(vAH9 A(A(A(p|A(vAHE Ah1S    8AWi    iiiA(#bA(R_1A(91AH9By BBBiA(A(vAHf- AH A(|A(r~AHJ AHJO <A(r~A(|AAiA}} } A} A A}} A}    A(,btAhV    @AhT  Ah\' A(R_Ac: c :::U (AhB(\ AhHI} ! ###;AhCO $ &&&@AhC9o ;;;D FFF`AhBK PPPY [[[wA(|A(r~A(9|A(rA(&XlA(&XlAH a   #AHaU A(BeqqA(} {q{Ĝ=3=髺=Ȝ==#l=ۻ=sʜ= k=k= {=0=;^=Q= =s=#8==:#:ɜ=3=髅=C={J=C=k+= /=;]=S,=:=髻=㲣=[=飔={===3͜=={=+t=ӻ=K==*=S==3= =s=۷=飻= ==>=ĥ=h:h:K:k:k:4=:C:K=#R=KQ=ý=K|=c=={*=*==+*=@=;*=:铙:=%=?=={=Ƨ=;r== =A=KZ=CC==~==k:;= '===;=S&=Ƥ=3==-=-=C=Kc=3=T:S>;T:=K::ޤ=ʜ=j=Ɯ=6==c-=[=c=K=c#=s?:S:鋷=E=:=;=郫==Sӝ=Ι=#=d=s?=+R=s=*=C#=%="=3==+:s:+:=C#==KU=s=K̥=s=K=C= =sۦ=@=-=.=&=e==雨=D=K¤==k'=5:K:c'=k\::;::&=$={=C=k^:u=^:={ץ=-=#"==[=۞=1=c=K=c=鋋==#=3b=|= = 6=s.=[==K====+==3+=J=6=3b=ۦ=鳟=+G=F=0=S{=kD=S؞="="={8:E:=p=kp=>k=>>3J>=>=c= =s%= =w: O=; =:{:kh:SGU:k=33 >=Sm=[=3=c'=L=# =s=S'=3=&=铓=k=&==3=>=&= ">C">cJ=\=髰=s=p=#=,=Ü==E=;=E=E=C=֞=֞=M==+L=c=ߤ=s=+מ=מ=D==F=#J=黲=c====C=l=l={>S={> >k >C ={ > > >c > >c === =s >cP=T===*=3'=;'='=#'=+'=k= j=;=ӕ=K;==ˬ=x==)===;ș=;ș=>>k>>b=Á=٥==k >ý > c=ӽ > > > >3 >K >;=[ > ;=k > >˻ >=+ > >黼 >s= > >黻 >铻 >N=KO=3O=O=O=N=N=KN=[=R=3]=]=\=\=\=\=™=™=™=KN=N=N=N=N=======髮=S > >+:=˥ >:=˦ >Ӳ=; >ӣ >Cę== >= >铤 >[=3= ==黊==鋊=#=;=Ӊ=髉=C=ۈ=s== =;=飰==\:+\:s\:K\:\:A=E=A=H=D=\=CP=kZ=雂 >郂 >˂ >铁 >ۂ >铂 >雑=铁 >ۂ >s >郩=[\=S'=;'=S'='='=#'=+'=3'=cX=KX=Z=1:1:s1:{1:1:;} >} >| > >;} >V=K} >~ > >K=S=[=c=c=%=郹=髜==黱=Z=;s=r=r=s=r=r=c%=r=C%=r=r=r=r==雖=)>{W=U=鋈:!:髞m:s:+;::[q:3m:{m:铛m:髛m:S:黛m:雪:[g:;U:U:{>U:>U:>U:?U:K?U:́cNf'd3-%0.e@XA)8O "5stBC&Qvz,x(ag6{}|I:B@I:B@I:B@I:B@I:B@l:BI@:B@xI:B@hI:B@XI :B@HI:B@8I:B@(IH:B@I:B@I:B@Ip:B@I(:B@Iྏ:B@Ih:B@Iԏ:B@IՏ:B@Iԏ:B@IhՏ:B@xIHԏ:B@hI Տ:B@XI:B@HI:B@8;̙3̡+̝8:BI:B@Ip:B@Ih:B@Ix:B@I:B@I :B@@:BIH!:B@I!:B@Ip8:B@pI88:B@`I8:B@PI7:B@@Ip>:B@0I>:B@ I>:B@I ?:B@IX?:B@I(Z:B@IY:B@IY:B@I`Z:B@IY:B@5 m:BI@:B@I`:B@pI:B@`kc:BSKHt:B;:B+# :B t:B:B 0:B Ȑ:B `:B{skc[SK C#(u:B34+#> C H M * R  W\/a%fk:B{s :Bc[S 0:BI:B@(I8:B@IX:B@ Ȗ:B :B v:BȘ:B{sk :BIP:B@@Ip:B@0I:B@ +8:BI蚏:B@I:B@I(:B@К:BI:B@I:B@I:B@h:B:BIP:B@pI0:B@`I:B@P[SKC :B3+# :B  :B:BI`:B@I@:B@I :B@ 螏:BIx:B@`I:B@PI:B@@Kh:B;3+# :B$ (, 0  4 8 <@DHx:Bskc [S :BCvY;X3yW+V#{UT~S ŔQP̄OṄML̊KJ̍I"H̐G'F̓E-D̖C3B̙A{9@s̜?k>>c̟=[CkvcF[zSNK~C;̂3+̆#*̊: ̎ J ̒  ̖2̞̚B̢"̦ȴ:B {s:Bc [SKC;3 +#"X:BI:B@I:B@Ih:B@I :B@I:B@I:B@IH:B@I:B@I:B@pIp:B@`I(:B@PIྏ:B@@I@:B@0;# 3 +*#1 8?C:B !:B {sk$c[(S K,C;0Ï:B+B#F  JN2 R : V  Z.^>b6fjŏ:B{skc [SKHɏ:B;`ʏ:B+# ʏ:B.2 6: > & B  FJ*N"{RskVHˏ:B[SKC Ώ:B3 +#$ (  ,  048 <@pϏ:Bя:B{sxҏ:BIԏ:B@HIԏ:B@8C;3+#(ӏ:BIՏ:B@IhՏ:B@IHԏ:B@I Տ:B@ ֏:B ֏:B {# s k' c [+SK/C;33+7#=׏:B ُ:B   !%)- 10ڏ:B{ skc[SKCۏ:B3 +#  Xݏ:B ޏ:B xޏ:B ߏ:B{sk c [# S K& C ;)3++#.  14ߏ:B " $  '  + /{3sk5c[7:BKC ;3+#:B  :B X:BI:B@Ix:B@ :BI:B@x{:BI:B@PIh:B@@IH:B@0I@:B@ I :B@:BI`:B@:B    "*.{2:Bk%c([ S+ K C. ; 32+ #6: >"B:BI:B@I:B@LOS$W4[<{_sDkccI [g S Kk C8 ;o3H+s#1w {@0:B  !%) -p:B{s"k c% [ S* K C/;32+#6 : >:B)-1 59=! A  E { sHkcK[ SOK%CS;3W@:BIp:B@I:B@=<̂;:̆9#8̊7'6̎5-4̑332̕1906/=.D-{A,sI+k̥*cQ)[̩(SY'K̭&C`%;̱$3f#+̵"#l!̹ t ̽{ *ۿӿ˿ÿM軿賿]諿裿i蛿蓿x苿胿& { sG k cc [SKCU;30+#p8:B #' + ۾ Ӿ. ˾ þ1軾賾4諾裾7蛾蓾:苾胾=H:BIh:B@XcC[ SGKCK;3O+##S+W 3[;_ c ۽ ӽg ˽/ ýk軽?賽o諽'製s蛽蓽w苽7能{h:BIx:B@Xc[SKC;3 +(:BI:B@  :B ۼ Ӽ ˼ü 軼購諼裼蛼#蓼 苼':B{s @ :Bc[ SK :BI :B@ +\*#)`(' c&%f$##i"+!ۻl ӻ3˻pû;軻t賻C諻x裻K蛻|蓻Q苻̀胻Y{̄sk̈c'[̌S7K̏CG ;̒ 3U +̕ # ̘? ̛̟Ṇ/ۺ̦ :B˺:B軺$賺諺(裺蛺+蓺 苺.胺 {1 s k5 c [8SK;C ;>3+A# D@:B '*-۹0ӹ˹3ù 軹7 賹$ 諹; 裹 蛹?蓹苹C胹{Gs kKc[N:BKC; 3+ #@:BH$#L"!P ۸ӸT˸øX軸 賸\諸(裸`蛸0蓸d苸8胸h{@slkcp[SsK$ Cv ;4 3y +D #}̀ <̃,̆ ̉:Bӷ ˷ ÷軷賷諷裷蛷:B苷胷 :Bs:Bc [SKC ;3+#0 :B $( ۶, Ӷ ˶/ ö 軶3賶 諶7裶蛶;蓶苶?胶{C!:Bk0$:B[ SKC;3+h$:B  H%:B  ۵ӵ˵õ%:BI&:B@阵I':B@鈵I0':B@x胵{&:Bkcp':BI(:B@8I':B@(I':B@#&* . 26 ۴: Ӵ" ˴> ô 軴B賴諴F裴蛴J蓴苴N胴{R@(:Bk+:B[S+:BIh,:B@(IH,:B@I,:B@,:BIx-:B@I-:B@سIX-:B@ȳӳ˳-:B軳賳-:BIh.:B@鈳IH.:B@xI(.:B@hI.:B@XI/:B@HI8/:B@8C;.:B+#x/:BI0:B@I/:B@I/:B@زI1:B@ȲI(1:B@鸲I0:B@騲賲諲0:B蛲蓲h1:BI1:B@hI1:B@XI1:B@HSKC ;3 +#82:B  ۱ӱ3:Bñ軱賱 諱裱 3:B蓱英胱{ sk 84:B[S4:BC;3+5:B p5:B ۰Ӱ ˰ð軰賰諰8:B蛰 蓰苰胰{skc9:BSK::B; 3+# @;:Bۯh<:B˯ï軯賯諯裯蛯蓯 苯<:B{=:Bk=:B[SKC ?:B3 + #    $(ۮӮ+H@:Bî 軮賮諮裮蛮蓮苮A:B{skB:B[SK`C:B;3+C:B D:B  ۭӭ˭í`D:B賭(E:B裭XE:B蓭苭胭{s E:Bc[SF:BC(;3,+#04  8 <  @۬ӬDˬ$ìH軬賬L諬 裬PpF:B蓬苬胬0I:BskcI:BSKCI:B3+#8J:B J:BJ:Bӫ˫ë8K:B賫諫裫K:B蓫苫胫K:Bsk8L:B[SKxL:B;3+L:B  (M:B۪M:B˪ê軪 N:B諪裪蛪N:B苪胪{s O:Bc[SK O:B;3+(P:B P:BP:B۩ө˩@Q:B軩賩諩Q:B蛩蓩苩Q:B{sk c[ 8R:BKC;3 R:B#`S:BS:BۨӨT:Bè軨賨hT:B裨蛨蓨苨胨 T:BskcHU:BS KC;3 +# !U:BV:Bۧӧ˧8W:B軧 賧 諧裧蛧蓧 苧胧{sk"W:B[SK C; X:B+#  Z:B ۦӦ˦æ軦[:B諦裦蛦 蓦苦\:B{$sk(c[,S K0C ;4 3 +8 # < @ DH ۥL]:B˥ å軥賥諥裥蛥 `:B若a:B{ s k c [ SKC!;3%+#)-Ha:B(c:Bۤc:Bˤäd:B賤+諤/裤蛤3蓤 苤7胤{;sk?c# [C S KG C ;K3+O#S' W[d:Bh:BIxh:B@鸣IXh:B@騣Ih:B@阣I(i:B@鈣IHi:B@xIhi:B@hskh:B[SKC ;3 i:B#   8j:BۢӢˢâ k:B賢諢裢k:B蓢苢胢k:BskcPl:BSKCl:B3O&+R%#$W#" Z! ]!`'ۡdӡ-ˡiá=軡̗賡l諡D裡o蛡J蓡r苡胡u{sxk* c{ [@ S~ K C̄;$3̈+G#̋2̏ ̓ m:B   ۠" Ӡ ˠ%à軠*賠諠1裠蛠4蓠 苠:r:B0HX4VS_VERSION_INFO77?StringFileInfo040904b0>CompanyNameAutodesk, Inc.LFileDescriptionAutoCAD component8 FileVersion18.0.55.0.0x*LegalCopyrightCopyright (c) 1982-2009 by Autodesk, Inc.0ProductNameAutoCAD< ProductVersion18.0.55.0.0DVarFileInfo$Translation Hm (@@X(@(ȃ,DГ :BL!'X dʾL! zAD^@xvxOJP h"]lOSS;=:'xcI~ѡ& # #֥8p^@v"WJ =siFL6j#xcI~ѡ& # #gV{BWݒ I(﮴{`wۡUxcI~ѡ # #Gj&}{ D HދVI`}77JvŔÆmxcI~ѡ # #7H~ȩI 0%/rtrIq|K<3 xcI~ѡ##jc0OkZ:IXnT{xGμ}d(xcI~ѡ##SwE@+Iy9GyGjUsxcI~ѡ##+vܮM֨,Nn^'J DrB1AEgxcI~ѡ?'##O(K{cM^'Jxzx{WlM/hxcI~ѡ?'##d/&Bw=e0vEJ` i- Cb.ވxo+`zl> x##GrXyEm՞^'JL,9G;Joi1xcI~ѡ?'@<w[pBSJB v2.0.50727l#~L#Strings$#US,#GUID<#Blob@ 3  ' .:@H T j{mscorlibAcWindowsAdWindowsSystemWindowsBaseAcCuiacdbmgdAcMNUParserPresentationFrameworkPresentationCoreacmgdAcTcMgdMyAutoCADAcMrAcDxSystem.DrawingSystem.XmlSystem.CoreSystem.Windows.Forms /Ep _O 9"z\V418V6N5?_ :<PermissionSet class="System.Security.PermissionSet" version="1" Unrestricted="true"/> ?@@@X@s@ @@? @@$@@$@ @P@?UUUUUU?@@@y@@@@Y@@ @??@j@@x&?.@ 0B?i@$@33333h@@@b@ 0B?x&?@@$@33333h@i@x&?2@@2@@@2@@2@?O贁N{?@@\(\?b@@D@@b@{Gz?@^z?D@@$@@>0@X@@@?@I@`@?0HLHIMS I I(HLHMS I I0HLHIMS I IPR`lȂȂȂЂD܂Pkp! 0 o""U%`%)())D)&*D&*f*Dp*F,\P,@/pP//܂/X0܂`05252k2k22222P3`3<5@5 6Ѓ 6n666Ȃ6!70777j8p8r8Ȃ8 9999;:@:::k;p;<<<<0=@===[>`>>>??@ @@@KAPABBC0CCD]DpD)ED0E9EȂ@EEEE\FF\ FdFpFFЂFFЂFF܂G!Hh0H3I@IDQxPQQQQRRȂ RSSSȂT3T܂@TsT܂TTTV V)VȂ@V{__`Ą`=eԄPe9f@ff\f,i0iiĄip$pt@tu\uuЂuvpv0wЂ@ww܂wiiRR..qDw܂ 4Ȃ@׆XĄ` ܂3Ȃ@WȂ`\ҔЃȂȂ җȂ#Ђ0`\p\Ȃ܂  Ȃ ~yxQ܂`\Ы\Ȃ8܂@x܂܂ipȂȂ܂E̅Pǵе (@ X\܂`Tp`܂u܂0}܂h܂p܂ JȆPdp0\`{\  R\`$$<0܂X"\0ȂȂȂЂCPp v܂`p~hpЇ\"0q܂ c܂pȂ~Ȃ\`bȂ/@p܂R`.@_Ђp܂ȂȂȂ %Ȃ@EȂ`܂_(pAPRȂ`܂@ЂQ`^@p܂Ђ!Ђ0 x  @ TN܂`l~Ą ܂\`r @ "X#`#Ђp###n&&(؈(-p -).p0.22W5@p56܂6$7Ѓ07c7p77܂7888Ђ88Ȃ99Ȃ 9: :;x;AXAAABBQBQBBBBBCCACPCCCDDDȂEEȂ E"EȂ@ExEЂEF F4FЂ@FFFGGHHI( IfI\pII@JJXJ&KX0K~KlKKXLpLlLL|LM\M_N\pNNN@OPOOOP܂0PP\PQRSSSSSȂSoT\TTȂT2X<@XY YdYpYY܂YYZ;Z܂@ZEZȂ`ZZ܂ZZȂZZȂZ^[p[[[[܂\F\P\\܂\^^7_@_````BaPaaЂa'd0d1e@eeegghh ii2j@jjЂjk\kbl܂llȂlm\m2m\@mLp`ppȉp}qqrȉ rrЂrsssȂtNtȂ`ttȂttȂttȂu;uȂPuuȂuuȂuvȂ vvvvЂvvȂvvЂv}؉}7}Ђ@}i}܂p}mXmȂȂ*06Ȃ@QЂ`eȂȂЂ€ȂM` dpbpxxЋnjЌxÏЏ ؒĄ~~06@܂  ȂşȂȂȂ epvȂ< tЃ܂;@~܂Ц]ĄpRTRp@pP}X`M`\ɹй@P|i$p Ȃ;܊@GP06Ȃ@ȂȂȂȂBPEP$ 8 Pl g܂pvȂȂ[`xvȂЂLЂP܂nxȂ  Ȇ MȆ`LlPl4܂@^Ԅp// ؋FF//]p z $ N ` p Ђ   DPЂ%0w8gxpЂȂ܂Y`}ЂHȂxIxP\Ȃ`bȂȂȂ 4Ђ@EȂ`eȂȂȂȂȂȂ 3Ȃ@WЂ`qЂȂ%0Ȃ  >!P!!!B"P""":#@#i#Ђp##Ђ##Ȃ##$ $Ȃ $z$$$$0%@%m%%%Ђ%"&0&&&&Ђ&('܂0'4'Ȃ@'(((Ȃ((Ȃ()))Ȃ)^*p**+++3,@,,܂,,Ȃ--Ȃ -$-Ȃ@-j.p....//Ђ0/P/Ђ`//`/!0009191q11W5l`55Ђ55Ȃ56 6667 7t7܂788::::G;P;4<@< AA>AЂPAA܂AAAjDjDDDDDDDEEEEFF G܂ G&GȂ@GTGЂ`GfGȂGGЂGGȂGGȂGIIIЂIJJJJK܂ K9KЂ@KKKKȂKKȂLLЂ LLLMN`NNNNЂO(P0PPPQQ@RPRSSSЂSuTTTЂTTЂTIUPU\UȂ`UbUȂUVW WȂ W"WȂ@WWWWX`XXX4Y@YYY[x[l\p\r\Ȃ\"]0]]]^^_ `;`Ȃ@`$bx0bbbbȂbbȂbbȂccȂ cc܂ccЂdfxf^gpgg܂gi\i0j܂@jFjȂ`jlxmmmmȂndnpnIoPoo܂o=pPpp܂pq܂ qIq܂PqqqrЂ rtpttȂuuȂ uGuЂPuUuȂ`ueuȂuuȂu,v0vvvw̌ wwww̌wxЂ xxyyy2z@z{{{Ȃ|||~ ~~~?P ~ȂȂ ́܂څ †ІR`Ђ܂ ׎5܂@ Ȃ KP0HЂPɜ܂МҜȂȂȂ ܂sȂy:@NȂ`qȂȂȂѧȂȂȂ 1Ȃ@Ąp`phpĄ (Ȃ@܂Ȃ )Ȃ@g܂pȂȂȯȂȂ<Ђ K܂PXȂ`hȂȂz܂{\`:x@fpλ 08Ȃ dp}?P &x0p:@\0Ǔ`Ȃh|#0\`oȂЃЃЃ 1@1@DȂdpȂ 6 @v4#0ЃЃ 5@H`p܂Tx`^p"0y  Ў   V`܂!ȉ0 h ^pTpp?pPBP% 0     ."Ѓ@"""|##9$@$$%#%Ђ0%%%&p& ' ''''Ȃ'(((Ђ()h))܂*-4-.܂ .0<111 2܂27T77Ђ77Ђ7\8`8f;tp;>>>Ȃ >Ap AAABBCCCĄCD܂ DOD܂`DhDȂDDȂD E܂EEFFЂ FsFFG0GDGЂPGVGȂ`GeGȂGGȂGGȂGGȂGHHIIJ܂ J)JȂ@JHJȂ`JJlJ LLLMFSPSSSSЂSSЂTaaaȂaSbĄ`bcĄ clcpccc(d0dddeȂeeȂ eVeЂ`ee܂eeЂemjjjЂjjȂjjȂjnȆ nnnvlvvЂwCxȉPxxxzpzl|p|}Ą}{}}}Ђ}}܂~~Ђ0~~܂~~Ђ~~ЂЂ0DЂP؏`p܂+0܂ƎЎ܂ tЃ"40LP܂܂ٖȗȂȂ  mÚ܂К-@HȂ`hȂȂȂ܂ȂʜȂkp?P 0ĥ@Х\ŦЂЦȧxЧ܂ ШgpȂIPxЫS` ̭Э*܂0ip܂A\PoЂȂȂ0ipDZЃб܂ t Ʒ܂зS܂`܂1܂@Ѓ܂)0܂ɺк*܂0ipʻ܂л j܂pǼЃм܂ Y`܂Z܂`eȂȂȂžȂ܂ &Ȃ@FȂ`eȂȂȂȂgpȂȂ 3@ЃȂ"Ђ0`܂p܂CPRȂ`܂ȂȂȂȂ &Ȃ@TЂ`fȂЂȂȂȂȂ 4Ђ@"01@]p<@!܂0a܂p+0ȂЂU܂`Zx`C$C܂bȆp܂&0j܂p Ѓ!0AЂPz܂Ȃ܂6@܂ЂZ``bȂ̐ȂN`hȂ0@ЂЂBP  J܂Po#0:܂@y܂^܂px @ЂP܂=P܂S܂`܂ ( &Ȃ@Ȃ ȂȂȂȂȂ &Ȃ@FȂ`ȂȂȂ r2@Ђ܂Ȃ "Ȃ@bЂpЂЂȂHȂT` ĄȂ &Ȃ@\PȂ`Ȃ J\PЂ02Ȃ@j\pЂȂ# 0  Ђ < Ђ@ j \p    Ȃ  Ȃ c p  Ą  \ " Ȃ@ , l0  Ą | lȂ _pȂȂ 4Ђ@FȂ`tЂȂЂȂȂȂ %Ȃ@FȂ`tЂЂȂЂȂЂ "Ȃ@FȂ`tЂȂȂ &Ȃ@^ЂpЂ$ z܂ЂЂ2@N`܂ЂȂЂ-@Nx`' @0 v    (!0!!!>"P"v"Ђ"w$ $% %R%܂`%e%Ȃ%%Ђ%%܂&M&`&&&&''Ȃ ')'Ȃ@'''2)@)~)))Ђ))Ђ).*@*Q*Ђ`*t*Ђ**Ȃ**Ђ**Ȃ**Ȃ+O,`,,,-܂-C-ȂP-w-Ȃ--.].p.//01112ȉ 2T3x`33455777Ђ88x8f9p999 :܂:I:P::܂:;;<<<Ђ=>>??@@-A@AqA\AA܂AAȂAA܂AAȂBACPC|C܂CCȂCDDDȂEEЂ E&EȂ@EBEȂ`EEĄF)F\0FVFЂ`FtFЂFFȂFFȂFFЂFG\ G&GȂ@GHHHȂH I\0IIhIIȂJJЂ JTJЂ`JJЂJ[K`KKЂKKЂKLЂ LTLЂ`LLЂLLЂLMЂ MTMЂ`MMЂMMЂMNЂ NTNЂ`NNЂNNЂNQؑQ!R!R]R]RRRRRTS`SSЂSThTT\TTȂUUȂ UYU\`U5Vh@V(Wh0WiW\pWrWȂWZZZȂZZȂZ [܂[[Ѓ[[Ȃ[[Ȃ\,\܂0\\Ѓ\ ]܂]]Ȃ ]Y]\`]^^^Ȃ^^܂^ _\__h``Ȃ `"`Ȃ@`L`Ȃ``bbbccȂ cLc܂PcRcȂ`cc܂ceeee;f@f@h,Ph|h܂hl@llȂllЂmmȂ mNm`mbmȂmmЂmmmmȂnnnn܂nnȂooȂ o4oЂ@oFoȂ`oYp0Ypppqq$qЂ0qzq܂qqȂqq܂q:r܂@rrЂrrЂr9sЃ@ssЃsuuuȂ uuTuuȂuuЂuv\v>D>>v>D>>>>?;?P?{?????@;@P@{@@@@@A;APA{AAAAAB;BPB~BBBpB&Cp&CqCpqCCpCCpCQD>QlQDlQQDQR RVRVRRRRR S SES`SSSSSSS.T@T|TTTTU U`UpUUUUUKVKVVVWWTWȆ`WWWWW X XoXoXXXYYSY`YYYYDYKZD`ZZ Z[0[f[[[[\ \X\p\\\\]B]ȆB]t]Ȇ]]]]]9^P^^^^^C_C_____``V`p`` ``aDaPaaaabSb`bbȆbbpb0cp0ccpcc(cd( dfdddde efeDeeeef=fPfffggNgNgggg g!h 0hphphhhhh:iPiiiiiiij0jVjpjjjjj'k%@kmkkkkkl+l@lmllllmm@m@mmmmmmn2n@nnnnnno.o@oroooooo&p@ptpppppq&q@qmqqqqqr5ʍAݎ'-2$N59/[Z2 q~RqLj[}㶑FG#{Y^羝,ʆ,ʙĺ̙~EE.ԁ B8ًoۜ޴W:67FV`Q{\,HEWrZ}N .6ӗ[a C b u V-u?O;f4! < ^(*,&0Q2'8Y89S9Ϙ;X?leBD`eEI=?LƇMQUAQST̄TUcGUVsXQY]`ՖddNe`@gݡgKii~[Bk¡p}rI^təvuvw 3|)&~՘&~iƨT"|k ;$r&h% 'v6! c "%=2 `#? $9& $s["&n()##   8> R{ 6%* RH "c!c# BR 1"Yg m!u!#Z#5h+0appframe/acappframe.baml^infocenteracconn/cuiribbonmigrationballoon.bamlmLinfocenteracconn/myautocadballoon.bamltJquickview/controlpaneldictionary.baml#{0quickview/quickview.baml@resources/frameworkresource.baml>Bresources/images/arrow%20left.icoDresources/images/arrow%20right.ico4resources/images/close.ico@resources/images/commandline.icoFresources/images/content_search.bmp Bresources/images/drawingclose.icoK@resources/images/drawingsave.ico2resources/images/help.pngQresources/images/layoutplot.ico%Dresources/images/layoutpublish.ico/@resources/images/layoutthumb.png4>resources/images/menu/1_fog.icoA@resources/images/menu/1_help.ico W@resources/images/menu/1_hide.icoGlBresources/images/menu/1_image.icoDresources/images/menu/anav_web.bmpVresources/images/menu/close%20-%2032x32.icobresources/images/menu/close%20-%20all%2032x32.icojresources/images/menu/close%20-%20current%2032x32.icoxresources/images/menu/close%20-%20file%20browser%2032x32.icoCresources/images/menu/drawing%20utilities%20-%20file%20browser%2032x32.icozresources/images/menu/drawing%20utils%20-%20audit%2032x32.icoresources/images/menu/drawing%20utils%20-%20dwgprops%2032x32.icozresources/images/menu/drawing%20utils%20-%20purge%2032x32.icoresources/images/menu/drawing%20utils%20-%20recover%20-%20drawing%2016x16.ico)resources/images/menu/drawing%20utils%20-%20recover%20-%20drawing%20with%20xrefs%2016x16.icoM.~resources/images/menu/drawing%20utils%20-%20recover%2032x32.icoH8tresources/images/menu/drawing%20utils-%20units%2032x32.ico IXresources/images/menu/export%20-%2032x32.icoYzresources/images/menu/export%20-%20file%20browser%2032x32.icojRresources/images/menu/new%20-%2032x32.icoT{^resources/images/menu/new%20-%20dwg%2032x32.icotresources/images/menu/new%20-%20file%20browser%2032x32.iconresources/images/menu/new%20-%20sheet%20set%2032x32.ico!Tresources/images/menu/open%20-%2032x32.ico`2`resources/images/menu/open%20-%20dwg%2032x32.ico#Cvresources/images/menu/open%20-%20file%20browser%2032x32.icorresources/images/menu/open%20-%20import%20dgn%2032x32.icopresources/images/menu/open%20-%20sheet%20set%2032x32.icoTresources/images/menu/plot%20-%2032x32.icoresources/images/menu/plot%20-%20edit%20plot%20style%20tables%2032x32.icojresources/images/menu/plot%20-%20manage%20plot%20styles%2032x32.ico- |resources/images/menu/plot%20-%20manage%20plotters%2032x32.ico0vresources/images/menu/plot%20-%20view%20details%2032x32.icoA^resources/images/menu/posttoseek_32_default.gifvRxresources/images/menu/print%20-%20file%20browser%2032x32.icoZresources/images/menu/publish%20-%2032x32.icobjresources/images/menu/publish%20-%203ddwf%2032x32.ico%|resources/images/menu/publish%20-%20file%20browser%2032x32.icofresources/images/menu/publish%20-%20pdf%2032x32.icoTresources/images/menu/save%20-%2032x32.iconvresources/images/menu/save%20-%20file%20browser%2032x32.ico1^resources/images/menu/save%20as%20-%2032x32.icojresources/images/menu/save%20as%20-%20dwg%2032x32.icojresources/images/menu/save%20as%20-%20dws%2032x32.icozjresources/images/menu/save%20as%20-%20dwt%2032x32.ico=resources/images/menu/save%20as%20-%20file%20browser%2032x32.icodresources/images/menu/send%20-%20email%2032x32.icoðlresources/images/menu/send%20-%20etransmit%2032x32.icovresources/images/menu/send%20-%20file%20browser%2032x32.icoI\resources/images/menu/sendto3dprintservice.gif Fresources/images/menu_nopreview.pngJ>resources/images/modelthumb.png4resources/images/panel.icoresources/images/search_cli.icoresources/images/search_tag.icoCFresources/images/search_tooltip.icoBH2resources/images/smgo.icoL2resources/images/smgo.pngHQ6resources/images/smloop.icoW6resources/images/smloop.png mCreates a DWFx file and allows you to set page setup overrides.$ EXPORTDWFXadw:ApplicationMenuItem_18$AcPublish_OutputTo3DDWF$ _3DDWF$ 3D DWF$3$7 1res:///%prodname%btn.xmx/$10/$RCDATA_16_3DDWF_BTN$7 1res:///%prodname%btn.xmx/$10/$RCDATA_32_3DDWF_BTN$P JCreates and displays a DWF or DWFx file of your 3D model in the DWF Viewer.$ _3DDWFadw:ApplicationMenuItem_19$AcPublish_OutputToPDF$ _EXPORTPDF$ PDF$P$9 3res:///%prodname%btn.xmx/$10/$RCDATA_16_PUBLISH_PDF$9 3res:///%prodname%btn.xmx/$10/$RCDATA_32_PUBLISH_PDF$C =Creates a PDF file and allows you to set page setup overrides.$ EXPORTPDFadw:ApplicationMenuItem_20$AcExport_DgnFile$ _DGNEXPORT$ DGN$G$8 2res:///%prodname%btn.xmx/$10/$RCDATA_16_DGN_EXPORT$8 2res:///%prodname%btn.xmx/$10/$RCDATA_32_DGN_EXPORT$< 6Creates one or more DGN files from the current drawing.$ DGNEXPORTadw:ApplicationMenuItem_21$AcExport_Other$ _EXPORT$ Other Formats$O$9 3res:///%prodname%btn.xmx/$10/$RCDATA_16_EXPORT_FILE$9 3res:///%prodname%btn.xmx/$10/$RCDATA_32_EXPORT_FILE.$/ )Export the drawing to another file format$ EXPORTadw:RibbonSeparator_3adw:ApplicationMenuItem_22$ AcPrint$ _PLOT$ Print.$P$H$5 /Output the drawing to a plotter or other device$ Print (CTRL+P)$3 -res:///%prodname%btn.xmx/$10/$RCDATA_16_PRINT$3 -res:///%prodname%btn.xmx/$10/$RCDATA_32_PRINT. adw:ApplicationMenuItem_23$ AcPrint_Plot$ _PLOT$ Plot$P$3 -res:///%prodname%btn.xmx/$10/$RCDATA_16_PRINT$3 -res:///%prodname%btn.xmx/$10/$RCDATA_32_PRINT$4 .Plots a drawing to a plotter, printer, or file.$ PLOTadw:ApplicationMenuItem_24$AcPrint_Publish$_PUBLISH$ Batch Plot$B$2 ,res:///%prodname%btn.xmx/$10/$RCDATA_16_PUBL$2 ,res:///%prodname%btn.xmx/$10/$RCDATA_32_PUBL$P JPublish multiple sheets or drawings to a plotter, printer, DWF or PDF file.$ PUBLISHadw:ApplicationMenuItem_25$AcPrint_PlotPreview$_PREVIEW$ Plot Preview$R$9 3res:///%prodname%btn.xmx/$10/$RCDATA_16_PREVIEW_NEW$9 3res:///%prodname%btn.xmx/$10/$RCDATA_32_PREVIEW_NEW$0 *Displays the drawing as it will be plotted.$ PREVIEWadw:ApplicationMenuItem_26$AcPrint_ViewPlot$_VIEWPLOTDETAILS$#View Plot and Publish Details$V$K Eres:///%prodname%btn.xmx/$10/$RCDATA_16_VIEW_PLOT_AND_PUBLISH_DETAILS$K Eres:///%prodname%btn.xmx/$10/$RCDATA_32_VIEW_PLOT_AND_PUBLISH_DETAILS$@ :Displays information about completed plot and publish jobs.$VIEWPLOTDETAILSadw:RibbonSeparator_4adw:ApplicationMenuItem_27$AcPrint_PageSetup$ _PAGESETUP$ Page Setup$S$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_PLTSET$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_PLTSET$c ]Controls the page layout, plotting device, paper size, and other settings for each new layout.$ PAGESETUPadw:ApplicationMenuItem_28$AcPrint_ManagePlotters$_PLOTTERMANAGER$Manage Plotters$M$6 0res:///%prodname%btn.xmx/$10/$RCDATA_16_PLOT_MGR$6 0res:///%prodname%btn.xmx/$10/$RCDATA_32_PLOT_MGR$U ODisplays the Plotter Manager, where you can add or edit a plotter configuration.$PLOTTERMANAGERadw:ApplicationMenuItem_29$AcPrint_ManagePlotStyles$_STYLESMANAGER$Manage Plot Styles$N$< 6res:///%prodname%btn.xmx/$10/$RCDATA_16_PLOT_STYLE_MGR$< 6res:///%prodname%btn.xmx/$10/$RCDATA_32_PLOT_STYLE_MGR$M GDisplays the Plot Style Manager, where you can revise plot style tables.$ STYLESMANAGERadw:ApplicationMenuItem_30$!AcPrint_EditPlotStyleTables$ _PLOTSTYLE$Edit Plot Style Tables$E$< 6res:///%prodname%btn.xmx/$10/$RCDATA_16_EDITPLOTSTYLES$< 6res:///%prodname%btn.xmx/$10/$RCDATA_32_EDITPLOTSTYLES$k eControls the named plot styles that are attached to the current layout and can be assigned to objects.$ PLOTSTYLEadw:ApplicationMenuItem_31$ AcPublish$_PUBLISH$ Publish.$U$J$& Share the drawing with a service$< 6res:///%prodname%btn.xmx/$10/$RCDATA_16_PUBLISHAIRDATA$< 6res:///%prodname%btn.xmx/$10/$RCDATA_32_PUBLISHAIRDATA. adw:ApplicationMenuItem_33$AcPublish_SendTo3DPrint$_3DPRINT$Send to 3D Print Service$3$; 5res:///%prodname%btn.xmx/$10/$RCDATA_16_SENDTO3DPRINT$; 5res:///%prodname%btn.xmx/$10/$RCDATA_32_SENDTO3DPRINT$E ?Sends solid objects and watertight meshes to a 3D print service.$ 3DPRINTadw:ApplicationMenuItem_34$AcPublish_Archive$_ARCHIVE$ Archive$A$5 /res:///%prodname%btn.xmx/$10/$RCDATA_16_ARCHIVE$5 /res:///%prodname%btn.xmx/$10/$RCDATA_32_ARCHIVE$6 0Packages the current sheet set files for archive.$ ARCHIVEadw:ApplicationMenuItem_35$ AcSend$ _ETRANSMIT$ Send.$D$K$ Send drawings as a package$7 1res:///%prodname%btn.xmx/$10/$RCDATA_16_ETRANSMIT$7 1res:///%prodname%btn.xmx/$10/$RCDATA_32_ETRANSMIT. adw:ApplicationMenuItem_36$AcSend_ETransmit$ _ETRANSMIT$ eTransmit$E$7 1res:///%prodname%btn.xmx/$10/$RCDATA_16_ETRANSMIT$7 1res:///%prodname%btn.xmx/$10/$RCDATA_32_ETRANSMIT$? 9Creates a package of drawing files and their dependencies.$ ETRANSMITadw:ApplicationMenuItem_37$ AcSend_Email$ Email$S$2 ,res:///%prodname%btn.xmx/$10/$RCDATA_16_SEND$2 ,res:///%prodname%btn.xmx/$10/$RCDATA_32_SEND.$; 5Sends the current drawing file as an email attachment$ ETRANSMIT#Z$1+NativeFunctions[%prodname%.exe|OnSendEmail]adw:ApplicationMenuItem_38$AcDrawingUtilities$Drawing Utilities.$V$# Tools to maintain the drawing$> 8res:///%prodname%btn.xmx/$10/$RCDATA_16_DRAWINGUTILITIES$> 8res:///%prodname%btn.xmx/$10/$RCDATA_32_DRAWINGUTILITIES. adw:ApplicationMenuItem_39$*$AcDrawingUtilities_DrawingProperties$ _DWGPROPS$Drawing Properties$D$@ :res:///%prodname%btn.xmx/$10/$RCDATA_16_DRAWING_PROPERTIES$@ :res:///%prodname%btn.xmx/$10/$RCDATA_32_DRAWING_PROPERTIES$B 8NativeFunctions[%prodname%.exe|OnDrawingRecoveryManager] acw:QATItemCollection_1$0 New$AcQATNew$ New$ New..$1 +res:///%prodname%btn.xmx/$10/$RCDATA_16_NEW8 $ NEW#Z$,&NativeFunctions[%prodname%.exe|OnQNew] Open$ AcQATOpen$ Open$ Open..$2 ,res:///%prodname%btn.xmx/$10/$RCDATA_16_OPEN8 $ OPEN#Z$,&NativeFunctions[%prodname%.exe|OnOpen]  DWGConvert$AcQATDWGConvert$ DWG Convert$ DWG Convert..$8 2res:///%prodname%btn.xmx/$10/$RCDATA_16_DWGCONVERT$ DWGCONVERT#Z$2,NativeFunctions[%prodname%.exe|OnDwgConvert] Save$ AcQATSave$ Save$ Save..$2 ,res:///%prodname%btn.xmx/$10/$RCDATA_16_SAVE8 $ SAVE#Z$Commands[^^C^^C_QSAVE] Undo$ AcQATUndo$ Undo$ Undo..$2 ,res:///%prodname%btn.xmx/$10/$RCDATA_16_UNDO8 $ UNDO Redo$ AcQATRedo$ Redo$ Redo..$2 ,res:///%prodname%btn.xmx/$10/$RCDATA_16_REDO8 $ REDO Plot$ AcQATPlot$ Plot$ Plot..$3 -res:///%prodname%btn.xmx/$10/$RCDATA_16_PRINT$3 -res:///%prodname%btn.xmx/$10/$RCDATA_32_PRINT8 $ PLOT#Z$Commands[^^C^^C_PLOT] Match Properties$AcQATMatchProp$Match Properties$Match Properties..$3 -res:///%prodname%btn.xmx/$10/$RCDATA_16_MATCH$3 -res:///%prodname%btn.xmx/$10/$RCDATA_32_MATCH8 $ MATCHPROP#Z$Commands['_matchprop]  Publish$ AcQATPublish$ Batch Plot$ Batch Plot..$2 ,res:///%prodname%btn.xmx/$10/$RCDATA_16_PUBL$2 ,res:///%prodname%btn.xmx/$10/$RCDATA_32_PUBL8 $ PUBLISH#Z$Commands[^^C^^C_publish]  Plot Preview$ AcQATPlotPrev$ Plot Preview$ Plot Preview..$9 3res:///%prodname%btn.xmx/$10/$RCDATA_16_PREVIEW_NEW$9 3res:///%prodname%btn.xmx/$10/$RCDATA_32_PREVIEW_NEW8 $ PREVIEW#Z$Commands[^^C^^C_preview]  Properties$AcQATProperties$ Properties$ Properties8 $4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_MODIFY$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_MODIFY$OPMSTATE#Z$%SystemVariables[OPMSTATE].Value8  Sheet Set Manager$AcQATSSM$Sheet Set Manager$Sheet Set Manager..$1 +res:///%prodname%btn.xmx/$10/$RCDATA_16_SSM$1 +res:///%prodname%btn.xmx/$10/$RCDATA_32_SSM8 $SHEETSET#Z$Commands[^^C^^C_sheetset]  Render$ AcQATRender$ Render$ Render..$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_RENDER$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_RENDER8 $ RENDER#Z$Commands[^^C^^C_render] acw:QATItemCollection_2 adw:RibbonButton_1$AcQATNew$ New$ New..$1 +res:///%prodname%btn.xmx/$10/$RCDATA_16_NEW8 $ NEW#Z$,&NativeFunctions[%prodname%.exe|OnQNew] adw:RibbonButton_2$ AcQATOpen$ Open$ Open..$2 ,res:///%prodname%btn.xmx/$10/$RCDATA_16_OPEN8 $ OPEN#Z$,&NativeFunctions[%prodname%.exe|OnOpen] adw:RibbonButton_4$AcQATDWGConvert$ DWG Convert$ DWG Convert..$8 2res:///%prodname%btn.xmx/$10/$RCDATA_16_DWGCONVERT$ DWGCONVERT#Z$2,NativeFunctions[%prodname%.exe|OnDwgConvert] adw:RibbonButton_3$AcQATSSM$Sheet Set Manager$Sheet Set Manager..$1 +res:///%prodname%btn.xmx/$10/$RCDATA_16_SSM$1 +res:///%prodname%btn.xmx/$10/$RCDATA_32_SSM8 $SHEETSET#Z$0*NativeFunctions[%prodname%.exe|OnSheetSet]adw:RibbonItemCollection_1adw:ApplicationMenuItem_69$ AcHelpHelp$ Help.#Z$,&NativeFunctions[%prodname%.exe|OnHelp]adw:ApplicationMenuItem_71$AcHelpNewFeatureWorkshop$New Features Workshop.#Z$#Commands[^^C^^C_ai_invokenfw]adw:RibbonSeparator_8adw:ApplicationMenuItem_72$AcHelpAdditionalResources.$Additional Resources. adw:ApplicationMenuItem_60$ AcHelpSupprotKnowledgeBase$Support Knowledge Base.#Z$1+Commands[^^C^^C^^P_ai_product_support_safe]adw:ApplicationMenuItem_61$#AcHelpOnlineTrainingResources$Online Training Resources.#Z$*$Commands[^^C^^C^^P_ai_training_safe]adw:ApplicationMenuItem_62$!AcHelpOnlineDeveloperCenter$Online Developer Center.$ APPLOAD#Z$("Commands[^^C^^C^^P_ai_custom_safe]adw:ApplicationMenuItem_63$AcHelpDeveloperHelp$Developer Help.$ APPLOAD#Z$71Commands[^^C^^C^^P(help quote;acad_dev180quote;)]adw:ApplicationMenuItem_64$AcHelpUserGroup$'!Autodesk User Group International.#Z$,&Commands[^^C^^C^^P_ai_browse augi.htm]adw:RibbonSeparator_9adw:ApplicationMenuItem_65$AcHelpSendFeedback$ Send Feedback.#Z$*$Commands[^^C^^C^^P_ai_send_feedback]adw:RibbonSeparator_10adw:ApplicationMenuItem_66$ AcHelpCIP$%Customer Involvement Program....#Z$1+Commands[^^C^^C_CustomerInvolvementProgram]adw:RibbonSeparator_11adw:ApplicationMenuItem_67$ AcHelpAbout$ About.#Z$Commands[^^C^^C_about]adw:RibbonItemCollection_2adw:ApplicationMenuItem_70$ AcHelpHelp$ Help.#Z$,&NativeFunctions[%prodname%.exe|OnHelp]adw:ApplicationMenuItem_68$ AcHelpAbout$ About.#Z$0*NativeFunctions[%prodname%.exe|OnAppAbout]! MSBAML```D@AdWindows, Version=2.1.0.0, Culture=neutral, PublicKeyToken=nullF1clr-namespace:Autodesk.Windows;assembly=AdWindowsAutodesk.Windows  AcWindowsA;Autodesk.AutoCAD.AcInfoCenterConn.CUIRibbonMigrationBalloonRNWindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35WSPresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35^ZWindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\XPresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35F9http://schemas.microsoft.com/winfx/2006/xaml/presentation8x,http://schemas.microsoft.com/winfx/2006/xaml?src1clr-namespace:Autodesk.Windows;assembly=AdWindows2,System.Windows.Markup.XmlAttributePropertiesXmlSpace preserve StackPanel_1$ Auto$ Auto.+ TextBlock_1$ Auto$ 0,5,0,5q$ Wrap=  Cursor$ ArrowigUse the Customize User Interface (CUI) Editor to transfer ribbon customization from a previous release. StackPanel_2$ Auto$ Auto.+- Name$ m_detailText m_detailText$ Auto$ 0,5,0,5q$ Wrap= $ Arrow To transfer your ribbon customization, perform the following steps: 1. Enter CUIIMPORT at the Command prompt. 2. In the Customize User Interface (CUI) Editor, in the left pane, click the drop-down menu and open the customization file that contains the customized ribbon from a previous release. 3. In both left and right panes, expand the Ribbon node. Then expand the Tabs and Panels nodes. 4. Drag the ribbon tabs and ribbon panels from the left pane to the corresponding ones in the right pane. For more information, see - Name$m_theHyperLinkm_theHyperLink$?.&$Migrate and Transfer Customizations. !z MSBAML```D@AdWindows, Version=2.1.0.0, Culture=neutral, PublicKeyToken=nullF1clr-namespace:Autodesk.Windows;assembly=AdWindowsAutodesk.Windows  AcWindows82Autodesk.AutoCAD.AcInfoCenterConn.MyAutoCADBalloonRNWindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35WSPresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35^ZWindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\XPresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35F9http://schemas.microsoft.com/winfx/2006/xaml/presentation8x,http://schemas.microsoft.com/winfx/2006/xaml?src1clr-namespace:Autodesk.Windows;assembly=AdWindows2,System.Windows.Markup.XmlAttributePropertiesXmlSpace preserve StackPanel_1$ Auto$ Auto.+ TextBlock_1$ Auto$ 0,5,0,5q$ Wrap=  Cursor$ ArrowThe - Name$m_theHyperLinkm_theHyperLink$?.1/ Autodesk Partner Products and Services website53 contains a broad range of AutoCAD-based solutions. StackPanel_2$ Auto$ Auto.+- Name$ m_detailText m_detailText$ Auto$ 0,5,0,5q$ Wrap= $ ArrowAutodesk works together with thousands of software partners from around the world. These partners provide a broad range of fully integrated and interoperable solutions for every design profession. Use the Autodesk Partner Products and Services website to find and buy these solutions.! MSBAML```EAAcWindows, Version=18.0.0.0, Culture=neutral, PublicKeyToken=null3clr-namespace:Autodesk.WindowsAutodesk.WindowsD@AdWindows, Version=2.1.0.0, Culture=neutral, PublicKeyToken=nullX:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindowsAutodesk.Internal.WindowsRNWindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35WSPresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35^ZWindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\XPresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 ControlPanelPinOff UriSource .*QuickViewControlPanelBorderBackgroundBrush Color 2.QuickViewControlPanelButtonBorderBrushRollover 62QuickViewControlPanelButtonBackgroundBrushRolloverEndPoint StartPoint Color Offset '#QuickViewControlPanelButtonTemplate TargetTypeProperty Value TargetType Name Padding Name JRenderTransformOrigin ScaleX ScaleY AngleX AngleY AngleTXTYTriggersPProperty PValue TargetName QVControlPanel CornerRadiusJSnapsToDevicePixels Orientation  QVPinButton,&Autodesk.Internal.Windows.ImageAligner  QVCloseButton QVNewLayoutButton  QVPublishLayoutButton  QVNewDrawingButton  QVOpenDrawingButton  SMPlayButton  SMStopButton  SMLoopButton SMNewViewButtonF9http://schemas.microsoft.com/winfx/2006/xaml/presentation8x,http://schemas.microsoft.com/winfx/2006/xaml&srcclr-namespace:Autodesk.WindowsBadw:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindowsResourceDictionary_1%L & & <& g& & 77& & 7& ,7& 7& V7& 7& 7& & 7& 7& N 7&  7 BitmapImage_1$$../Resources/Images/PinOff.ico?SolidColorBrush_1$ #CCFFFFFFSolidColorBrush_2$ #FF7CBDCFLinearGradientBrush_3$ 0,0&$ 0,1&.GradientStop_5$ #FFD7ECF2$0QGradientStop_7$ #FFC2E2EC$ 0.50QGradientStop_8$ #FFDCEFF2$ 0.501QGradientStop_6$ #FFFFFFFF$1Q Style_3". Setter_16$1q Setter_24  Setter_17#  Setter_18$ Center= Setter_19$ Center= Setter_20$1q Setter_21ControlTemplate_4" .R$ mBorder Border_5$ Auto$ Auto$ -1,-1,-1,-1q$ 1,1,1,1q$ 2,2,2,2q._$ mContentContentPresenter_2$ Auto$ Auto$ 0.5,0.5&zVTransformGroup_1.~ScaleTransform_2$1Q$1QSkewTransform_1$0Q$0QRotateTransform_1$0QTTranslateTransform_1$0Q$0Q P Trigger_5@J IsMouseOver.. Setter_22$ mBorder8 Setter_25$ mBorder8P Trigger_7@d IsChecked$ trueY. Setter_13$mContentzVTransformGroup_2.~ScaleTransform_3$1Q$1QSkewTransform_2$0Q$0QRotateTransform_2$ -90QTTranslateTransform_2$0Q$0Q  Border_6$22$22$ Center=$1q$1 #CCFFFFFF #CC4D4D4D$ Center=.._ StackPanel_7$ Horizontal= Button_58.adw:ImageAligner_1$ Center=$ Center=._ Image_13$16$$../Resources/Images/PinOff.ico Button_88.adw:ImageAligner_2$ Center=$ Center=._ Image_22$16$%../Resources/Images/QVClose.ico Button_98.adw:ImageAligner_3$ Center=$ Center=._ Image_14$16$'!../Resources/Images/LayoutNew.ico Button_108.adw:ImageAligner_4$ Center=$ Center=._ Image_15$16$+%../Resources/Images/LayoutPublish.ico Button_118.adw:ImageAligner_5$ Center=$ Center=._ Image_16$16$*$../Resources/Images/QVNewDrawing.ico Button_128.adw:ImageAligner_6$ Center=$ Center=._ Image_17$16$+%../Resources/Images/QVOpenDrawing.ico Button_138.adw:ImageAligner_7$ Center=$ Center=._ Image_18$16$$../Resources/Images/SMPlay.ico Button_148.adw:ImageAligner_8$ Center=$ Center=._ Image_19$16$$../Resources/Images/SMStop.ico Button_158.adw:ImageAligner_9$ Center=$ Center=._ Image_20$16$& ../Resources/Images/SMUnloop.png Button_168.adw:ImageAligner_10$ Center=$ Center=._ Image_21$16$'!../Resources/Images/SMNewView.ico!} MSBAML```EAAcWindows, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nullC&clr-namespace:Autodesk.AutoCAD.WindowsAutodesk.AutoCAD.WindowsD@AdWindows, Version=2.1.0.0, Culture=neutral, PublicKeyToken=nullX:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindowsAutodesk.Internal.Windows/)Autodesk.AutoCAD.Windows.QuickViewControlRNWindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35WSPresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35^ZWindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\XPresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35F9http://schemas.microsoft.com/winfx/2006/xaml/presentation8x,http://schemas.microsoft.com/winfx/2006/xaml>d2http://schemas.microsoft.com/expression/blend/2006Hmc;http://schemas.openxmlformats.org/markup-compatibility/20066local&clr-namespace:Autodesk.AutoCAD.WindowsHadw:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindows- Name$ QuickViewCtrl UserControl_1$ Bottom=Z Resources  ControlPanelHolder 62QuickViewControlPanelButtonBackgroundBrushRolloverEndPoint StartPoint Color Offset 2.QuickViewControlPanelButtonBorderBrushRollover Color *&QuickViewThumbBorderBackgroundRollover +'QuickViewThumbBorderBackgroundBrushIdle '#QuickViewThumbBorderBorderBrushIdle +'QuickViewThumbBorderBorderBrushRollover $ QuickViewThumbBorderCornerRadius "QuickViewThumbImageBorderBrush  QuickViewThumbImageMargin # QuickViewThumbnailOverlayButton TargetTypeProperty Value TargetType Name Padding TriggersPProperty PValue TargetName  ListBoxStyle1 CornerRadius Path Name,&Autodesk.Internal.Windows.ImageAligner NameStretchDirectionToolTip Name Orientation ElementName Mode*$Autodesk.AutoCAD.Windows.NameTextBox*$Autodesk.AutoCAD.Windows.NameTextBoxRenamedEditStateChangedMouseDoubleClick TextAlignment IsEditable  ActualText  ItemsPanelTemplate1!K IsItemsHost"$ Orientation  ListBoxItemStyle1#JSnapsToDevicePixels QuickViewLevelStyle-'Autodesk.AutoCAD.Windows.QuickViewLevel-'Autodesk.AutoCAD.Windows.QuickViewLevel$ MouseMove% MouseLeave& MouseEnter'PreviewKeyDown(PreviewMouseWheel LeftArrowButton RightArrowButton%& & !& & I& & & 1& Z& x& & 77& &7777 77 7 & & &  & & a StackPanel_8$ Left=LinearGradientBrush_3$ 0,0&$ 0,1&.GradientStop_5$ #FFD7ECF2$0QGradientStop_7$ #FFC2E2EC$ 0.50QGradientStop_8$ #FFDCEFF2$ 0.501QGradientStop_6$ #FFFFFFFF$1QSolidColorBrush_2$ #FF7CBDCFLinearGradientBrush_1$ 0,0&$ 1,1&.GradientStop_1$ #FFDCEFF2$0QGradientStop_2$ #FFD7ECF2$1QSolidColorBrush_1 #CCFFFFFFSolidColorBrush_5 #CC4D4D4DSolidColorBrush_3 #FF7CBDCFCornerRadius_12SolidColorBrush_4 #FF636363u Thickness_1 3,3,3,0q Style_5". Setter_26$ 1q Setter_52  Setter_27#  Setter_28$ Center= Setter_29$ Center= Setter_30$ 1q Setter_31 ControlTemplate_5" .R$ mBorder Border_7$ 0,0,0,0q$ 2q#z#z$ Auto$ Auto ._ContentPresenter_3$ Auto$ Auto P Trigger_9@J IsMouseOver.. Setter_32$ mBorder8  Setter_51$ mBorder8   Style_1".- Setter_8%@IsSynchronizedWithCurrentItem$ TrueY Setter_9 Z Setter_10$ 0,0,0,0q Setter_11 . Setter_12$ Hidden= Setter_35@ SelectionMode$ Extended= Setter_1 DataTemplate_1 DataTemplate.R$ mOuterBorder- Border_9888$1q._ StackPanel_4.+$ ImageBorder- Border_8$1q88 #01FFFFFF$ ImageWidth$ ImageWidth._$ ImageGrid Grid_1.+adw:ImageAligner_1$ Center=$ Center=._$ Thumbnail Image_1$DownOnly=$ Image$ ImageToolTip$ OptionsGrid Grid_2$ yHidden=$8q$ Top=.+$ LeftButton- Button_1$ Left=$ Top=8$LeftButtonToolTip.adw:ImageAligner_2$ Center=$ Center=._$ LeftImage Image_2$16$LeftButtonImage$ RightButton- Button_2$ Right=$ Top=8$RightButtonToolTip.adw:ImageAligner_3$ Center=$ Center=._$ RightImage Image_3$16$RightButtonImage StackPanel_5$20$20$ Horizontal=$ Center=$ Width$ ImageBorder$ Default=.+adw:ImageAligner_4$ Center=$ Center=._$FileIcon Image_4$16$ Center=$ Center=$ FileTypeIcon$ ImageTextNameNameTextBox_Renamed NameTextBox_EditStateChanged NameTextBox_MouseDoubleClicklocal:NameTextBox_1$ Center= #FF000000$TextBoxMaxWidthZ$IsImageNameEditable$ ImageName $ ImageNameItemsPanelTemplate_1.R$VirtualizingStackPanel_1!.$" Horizontal=$ 0,0,0,0q Style_2". Setter_6 ControlTemplate_1" .R$ border1 Border_3$4q._ContentPresenter_1##z##z#z- Style_4".;$QuickViewLevel_MouseMove;%QuickViewLevel_MouseLeave;&QuickViewLevel_MouseEnter;!'QuickViewLevel_PreviewKeyDown;$( QuickViewLevel_PreviewMouseWheel Setter_24  #01FFFFFF Setter_25$ Left= Style_7". Setter_36$ Left= Setter_37$ 8,8,0,8q Setter_38$ 24 Setter_39$ 24 Setter_40y$ Hidden= Setter_48 ControlTemplate_6.Radw:ImageAligner_5$ Center=$ Center=._ Image_6$("../Resources/Images/Arrow Left.ico Style_8". Setter_42$ Right= Setter_43$ 0,8,20,8q Setter_44$ 24 Setter_45$ 24 Setter_46y$ Hidden= Setter_49 ControlTemplate_7.Radw:ImageAligner_6$ Center=$ Center=._ Image_5$)#../Resources/Images/Arrow Right.ico) DataContext)SObjectDataProvider_1*S ObjectType;5Autodesk.AutoCAD.Windows.QuickViewDefaultDataProvider"*+S MethodName$+ GetQvDataListControlTemplate_2.R ,Name$, RootPanel StackPanel_3)$ Default=.+ -Name$- DefaultLevel Grid_3# .Level$.0.+ /Name$/ QuickList ListBox_1# # # $ Bottom=$ OneWay=$LeftScrollArrow Button_16#$RightScrollArrow Button_17#! MSBAML```EAAcWindows, Version=18.0.0.0, Culture=neutral, PublicKeyToken=null3clr-namespace:Autodesk.WindowsAutodesk.WindowsD@AdWindows, Version=2.1.0.0, Culture=neutral, PublicKeyToken=nullF1clr-namespace:Autodesk.Windows;assembly=AdWindowsAutodesk.WindowsX:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindowsAutodesk.Internal.WindowsC&clr-namespace:Autodesk.AutoCAD.WindowsAutodesk.AutoCAD.WindowsU/clr-namespace:Autodesk.AutoCAD.Internal.Windows!Autodesk.AutoCAD.Internal.WindowsOKmscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e0891&clr-namespace:System;assembly=mscorlibSystemRNWindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35WSPresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35^ZWindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\XPresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 booleanToVisibilityConverter  HelpImage UriSource  TestImage CloseFrameImage OptionsFrameImage SearchResultPanel SearchResultPanelItem SearchMatchInCLI SearchMatchInTag  SearchMatchInTooltip  MenuNopreview QuickPropertiesCloseMenuItem " QuickPropertiesOptionsMenuItem1+Autodesk.AutoCAD.Windows.AcadColorConverter  AcadColorToColorConv ColorItemTemplateDataType("Autodesk.AutoCAD.Windows.ColorItem Orientation Color Path Converter ColorControlStyle TargetType+%Autodesk.AutoCAD.Windows.ColorControlProperty Value2,Autodesk.Windows.RibbonCommandItemCollection QuickPropertiesFrameButtons("Autodesk.Windows.RibbonCommandItem!Autodesk.Windows.RibbonItem Id Text Image ToolTip71Autodesk.Private.Windows.ToolTipResolverConverter "SearchResultItemNameTextMargin uLeft uRight uTop uBottom "SearchResultItemPathTextMargin "SearchResultLocationForeground DisabledTextForeground DisabledImageOpacity #SearchResultItemContentTemplate4.Autodesk.AutoCAD.Internal.Windows.SearchResultColumnDefinitions,&Autodesk.Internal.Windows.ImageAligner Name Name Name4 .System.Windows.Automation.AutomationProperties AutomationIdTriggersBinding Value TargetNameF9http://schemas.microsoft.com/winfx/2006/xaml/presentation8x,http://schemas.microsoft.com/winfx/2006/xaml&srcclr-namespace:Autodesk.Windows8d2http://schemas.microsoft.com/expression/blend/2006Bmc;http://schemas.openxmlformats.org/markup-compatibility/20069adw1clr-namespace:Autodesk.Windows;assembly=AdWindowsCadiw:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindows0AcSrc&clr-namespace:Autodesk.AutoCAD.Windows8Acad/clr-namespace:Autodesk.AutoCAD.Internal.Windows.sys&clr-namespace:System;assembly=mscorlibResourceDictionary_1%& & (& U& & & 5& p& & & /& s& & & 2& V7 & 7& h77& 9& o& & & & 777777777 777"BooleanToVisibilityConverter_1 BitmapImage_1$Images/Help.png? BitmapImage_2$Images/test.png? BitmapImage_3$@:/AcWindows;component/Resources/Images/RibbonFrameClose.png? BitmapImage_4$C=/AcWindows;component/Resources/Images/RibbonFrameSettings.png? BitmapImage_5$#../Resources/Images/Panel.ico? BitmapImage_6$'!../Resources/Images/PanelItem.ico? BitmapImage_7$("../Resources/Images/Search_CLI.ico? BitmapImage_8$("../Resources/Images/Search_Tag.ico? BitmapImage_9$,&../Resources/Images/Search_Tooltip.ico?BitmapImage_10$,&../Resources/Images/Menu_nopreview.PNG?m)%MenuItem_QuickPropertiesCloseMenuItem$ Closem+'MenuItem_QuickPropertiesOptionsMenuItem$ OptionsAcSrc:AcadColorConverter_1DataTemplate_1".R StackPanel_1$ Left=$ Center=$ Horizontal=.+$ ColorRect ColorRect #FF000000$ Left=$ Center=$ 2,2,2,2q$12$12SolidColorBrush_1$ Color8$ DisplayName DisplayName$ Center=$ Center=$ DisplayName Style_1". Setter_1$ ColorItems Setter_2%@IsSynchronizedWithCurrentItem$ trueY Setter_38%!src:RibbonCommandItemCollection_1src:RibbonCommandItem_1$ ID_Close$ Close8 $ Close!src:RibbonCommandItem_Options$ ID_Options$ Options8 $ Optionsu Thickness_32$ 3Q$3Q$0Q$0Qu Thickness_33$ 0Q$3Q$0Q$0QSolidColorBrush_3$ #FFA8A8A8SolidColorBrush_30#ZX sys:Double_130.7QDataTemplate_4".R Grid_5 ColumnDefinition_9$ AutoColumnDefinition_10$ AutoColumnDefinition_11$*ColumnDefinition_12$ AutoColumnDefinition_13$ AutoColumnDefinition_14$ Auto .+$ mImageAlignersrci:ImageAligner_9$0$ Center=$ Center=$ 2,1,2,1q._$ mImage Image_4$16$16*Image+$ mText mText$ Left=$1# $ NoWrap=$ WordEllipsis=8$ Center=$ Center=*Text+$ mPathText mPathText$ Right=$28# $ NoWrap=$ WordEllipsis=$ Italic$8$ Center=$ Right=*Path+*Id+srci:ImageAligner_10$3$ Center=$ Center=$ 2,1,2,1qy*FoundInCommand+8._ Image_58$16$16srci:ImageAligner_11$4$ Center=$ Center=$ 2,1,2,1qy* FoundInTag+8._ Image_68$16$16srci:ImageAligner_12$5$ Center=$ Center=$ 2,1,2,1qy*FoundInTooltip+8._ Image_78$16$16 DataTrigger_12*Image+Z.a Setter_480$ mImageAlignery$ Collapsed=DataTrigger_10*Text+Z.a Setter_476$ mText*Name+DataTrigger_11$ false* Tag.IsEnabled+.a Setter_477$ mImageAligner8 @JOpacity Setter_478$ mPathText8  Setter_479$ mText8  !  ( @ 333EEEGGGJJJEEEEEEEEEEEEEEEEEEEEEDDDCCCv3330333MMM333?___333333,3335MMMRRR3337333?MMMEEE333<3330___JJJ333?3337333SSS333@333>>fff bbb~~~jjj              (  ||||||=========>>>===>>>===gggggg>>>===fffddddddfff>>>===eeejjjjjjccc>>>===hhhhhh>>>===gggggg>>>===ffffffffffff>>>===___eeeeee___>>>===```^^^```^^^>>>===>>>===>>>======sss<<<===>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>sss!6 h&  (  @ 666666666666666666666666666666666666666 666666666 666}}} 666}}} 666}}} 666}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}666}}}666}}}666}}}666}}}666}}}666}}}666 ( @  +8<278666666666666666666666666666666666666666666666666666666666666666666666 666  "}{{{ kkk]_`kkk kkk]_`ppp666 2?C(((:::666!666 ]_`rrr666666666666666!)6::::666}}}!666}}}  "}{{{{{{ kkk]_`kkk 666}}} 2?C(((666}}} ///}}} ZZZ}}} z|}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}666}}}666}}}666}}}666}}}666}}}666}}}666}}}666}}}666}}}666}}}666}}}666}}}666}}}666 !!! ! ! !8BM86(j> vݏ]4yrGR KDIDATsr Ns#`rֺg86cIYBHX XXP̅拯]DSޑ{nf@Nty}4{^u?AHI*}O 7PM'0{~DA^~Gs1(0%3m);9Z<0y Ar!]+he/_'_|v #g'O1vFeR29 HqyyZ f,KtIDAT0G$Q\Xhn} \ N>wz<s 3Ͽl+ ! !؞{OjmqI tKf 2PYnڡ75 Suxn66" ^1[,x;W PKϑ+Xka-@ 7zt{rjzN*zQ9<7PVJu㝋A'YH(`Ym`q,wO{b .# -?wlDA*k&IDATG1Z.W$1ny}m\+ks c`kv\>S4+^Ȇ';Aq\^HȌU0DZt Vi4A p%^~rrs =r]Rr 5P 10rm;m (5xlq˷=Z:@5VPZEaf& ۞Z8j}pdBA 4N/m^~|~pX:IDAT>>>>>>>>======FvvvvvFwww;;;<<>>>>><<<<<<<<<<<<<<<<<<<<<======<<<===<<<===<<<======<<<<<<<<<===<<<www;;;:::<<<;;;;;;<<asBIT|d pHYs  ~tEXtSoftwareAdobe Fireworks CS3FtEXtXML:com.adobe.xmp Adobe Fireworks CS3 2007-12-18T18:31:47Z 2007-12-20T19:26:12Z image/png X4tEXtCreation Time12/18/07#Xb+IDATxSǿcVb*^B$ =b1*|IrK*UJ!)r vydxve.Y$&v1LO0C~Mw5;a 孠 @ @qCP2 8d!(@qCP2 8d!(@qCP2 8d!(@q~&ǟnMӼ.aMzW{.ϢM޼y)|?pÕ4 hh8.G(r7!hn å4! b we`ٍ/fC-@E Ǎ/ߵhFǧP]]#R."y47\x`UVQoVVσ/]&ffchm7v;'&PxV]4PclS}2 4 0 \}x<ӧO;Ǜ,(#Wt7ҮO Mmlۮ_u@`^1lϰHÎGz;{`_ eM!K=`l(пk9*x/ÇZԦno zt>KWM/,%M,>رc{b/htzK8b@t:o@hOAzjV +gq毺]h4 zV<YB"++qjE6w ٽhGQ4Pcdn-~Am|Er0ǻ%S)<cg寚^߮k QAc.-[[[/0z:GL$k>>Ҳi|VE 4 p)ۯ}"5Eۤ]G{JKً>DϦiqeӋ64m(BW5[uo_Ήe#Zzv- L;<pk?0rK_-bSzzv4uthrNUmK_Alz|pwVX;W^YfD_zW';4c{{n.c]hC(^J&S.6SPW=aǫfǍ띶};T2,YA `ZX~tp2i~*%]HƘŰtMz ugjQWWk{q$v4}⎭>L":`4R/#^.ba\52 eY_L34h_J$~ޝ3AUE%7gV;Ei +-{뇃y?:t`r_o%XS3u1X Eb&9o~vrf<쓴Y:@fbrmY=ۘ/q>,ېXoZM| gl+?:t:'wSXMu~^\}Ǒre4#mPzv;C{`x VkVB c^)ҋ J~a') ,G477xyϔB{Pby__O{Ʈ(~!0Yz2)My| ۓB\᳿ֻe(W|V@Qrcȧ@X?  tiGDD.8)L@ulmmyY-za`d\B6y5G2K_?ʙ0p=|jB@!(@qCP2 8d!(@qCP2 8d!(@qCP24WsS)IENDB`!6h& (  @8*8*8*v‡‡‡‡‡‡‡‡‡‡‡‡8*8*8*A0~Z ĊĊĊĊĊĊĊĊĊĊĊ8*8*8*8*8*K8 0͜:͜:͜:͜:͜:͜:͜:͜:͜:8*8*8*8*8*8*8*l0խ]ױdk_XILJEխ]խ]խ]8*8*8*8*8*8*8*X޿ȏҵZ]]d޿޿޿8*8*8*8*8*8*B3 ĔУУҦnj`УУУ8*8*8*8*8*8*v?iԾΩΩΩݾ8*8*8*8*8*|d0TTTTT˵8*8*8*8*eP!TTTTTκ8*8*8*O=OTTTToЧЧЧЧ8*@0t]+OTTTT\ͣЧЧeP!JTTTTTaپTTTTTTóTTTV}Tlǩ޿( @ 5*5*5*5*6,:/ =3 _‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡5*5*5*5*7-;0 >4 I<‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡5*5*5*5*8-;1 ?5 B8]Jh‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡5*5*5*6+9.<2 ?6 C9F=I@THzĊĊĊĊĊĊĊĊĊĊĊĊĊĊĊĊĊĊĊĊ5*5*5*6,:/ =3 @6C:G>JAMEPHTL'ȓ)ȓ)ȓ)ȓ)ȓ)ȓ)ȓ)ȓ)ȓ)ȓ)ȓ)ȓ)ȓ)ȓ)ȓ)ȓ)ȓ)ȓ)5*5*5*7-;0 >4 A7D;H?KBNFQIUMw-36͜:͜:͜:͜:͜:͜:͜:͜:͜:͜:͜:͜:͜:͜:͜:͜:5*5*5*8-;1 ?5 B8E<H?LCOGRJUNYQ!\U#_Y&s3ѥLѥLѥLѥLѥLJwH{jF^VEѥLѥLѥLѥLѥLѥL5*5*6+9.<2 ?6 C9F=I@LDPHSKVOYR"]V$`Z'{=խ]խ]խ]ػMNQ8JAMEPHTLWP ZS"]W%aZ']ڶnڶnں|ȶǶ84 A7D;H?KBNFQIUMXQ [T#^X%b[(޿޿޿޿ǰu8JAMEPHTLWP ZS"]W%~ٳٳٳٳٳٳٳٳٳٳٳٳٳٳٳٳٳ5*7-;0 >4 A7D;H?KBNFQIUMXQ [T#T5*8.;1 ?5 B8E<H?LCOGRJUNYQ!|o=i˹6+9.<2 ?6 C9F=I@LDPHSKVOi_/hijkƳϾɫʫʬˬռ7,:/ =3 @7D:G>JAMEPHTLg]-chijjklmnopq7-;0 >4 A7D;H?KBNFQIZR"]ghhijklmnop8.;1 ?5 B8E<H@LCOGRJXffghijklmnnĝܼ9.<2 ?6 C9F=I@LDPHyIdefghijkllmšٸܼ:/ =3 @7D:G>JAi]/PcdefghijjktƠִٸܼ;0 >4 A7J@k]0WabcdefghhiqλЭӱִٸܼ;1 L@zi<[``abcdeffglʷ˥ΩЭӱrD`````abcddem̴``````abbcgӿ```````a```````]y````jŻ``wϹêʲ˳˳˳˳˳˳˳˳˳˳˳˳˳˳˳˳˳˳˳˳˳˳˳˳˳˳˳˳˳˳˳˳!6h& (  @drs9s9s9s9s9s9s9s9s9s9r?r?vUke6W%|Ls]$rB l9k9r?vj5rBo@j:Y(S$x`'sBn< k9r?e=t?xJxIp@j9V%{V{\U$wBxHr?o> \$kDzGQOxIk<],íɷP!zH}LwEsA`)lGOZXQrBd4`!Q!}LxFf.nIX`aX~Q_+ȱi.O}Ok3pMÑa—ggU{IzJY dzr=T"p<vRəhɞp`o|TzKM̻СV'PvA yWϠoѤxV_$OӬj>T$zG~YզsخUʶʝIJŭ[*b2P^٨vٯ׬dճհga+p@W$\ޭ{٭|۲֦wVз̹ȲŲSj4yKsE~CvݨuڧuԧtӡnMx n< l:j8h6g4f3f3f3f3sDɷ n; l:j7i5g4f3f3f3f3f3¤o@l=i9f5b1^/\,X(V$S"O}M|JyHwDtBq@ p> n< l:j8h5g4f3f3f3f3j8!xIsCo@l=h9e5b3_/\,Y(V%R"ϽtBr@p> n; m:j8i6g4f3f3f3f3uzKvGrDo@l n; l9j8i6g5f3f3f3o}NzLvHsDo@l n; m:j8h6g4f3f3iS}OzLvGsDoAl=i9f6c3_/\+|JyGwEtBs@p> n; l:k8i7h5f3iVS~OzKvHsDpAl=i:f6c3_/Ѿнϻͺv~M|JyGwFtCs@p> n< m:k8i7h5iZWS}P{LwHsDpAm=i:f7c2_0\,Y)W&S#Q~M{KyGwFuCr@q> o< l:k8i6j][VS~PzKwHsEpAl=i:f7{nDT"PN|KyHwFuCsAp> n< l:k9ka^ZWS~OzLwHsEpAm>i:zW&T"QM{KzHwEtCr@p> o< l:mea][WS~PzLwHtEpAm>έ̷Y)W&S#P M|KyHwFuCsAq> n= mieb^ZWS~OzMwItEqAƴؿÛwOZ)W&T#Q ~N|KyHwFuDs@p> oęlifb^[XT~PzLwItEwÛcY)W&T#P N}KzHwFuCs@pƜpØlieb^[WSP{LwItEӾǢչvZ)V'T#Q N}KzIxFuCrʟsǛpęlieb^[WS~Q{MxItE̴ԷϯZ*W&T#Q N}LzIxFs̢vɞsǜpęmieb_[WTP{MwItFuԷ̪cZ*W&T#Q N}LzIuϥy̢vʟsǜoęl]bb_[XTQ{MxIuFvչ^-Z*W'T#Q O}KwѨ}ϥỵvʟsǜp]Ǣz˩ɥƣvXTQ|MxIuFͫe6^-Z*W&T#Q!NxիҨ|ϥz̢vʠs`\XUQ|MxIӵoBa1].Z*X'U#R!z׮իҨ}Ϧz͢w[Ȧ\XUQ~Oǡi:e4a1^.[*X&U#|ٰ׮իҨ|ϥzcɤ~׼o\XUҺ˩l{CYᵍgzɵºV$[(`,e1k5p:v>{CGĆL;ɵºV$[(`,e1k5p:v>{CGĆLɵºV$[(`,e1k5p:v>{CGĆLɵºvP`,e1k5p:v>{CGĆLɵn6=cdf\IqCv>{CGĆLöW+6b|Hd)xo<Od-|Blm= f46b|Hd)xf4f4f4f4@`f4f4f4b|Hd)xf4f4`f4@}oxj@sc( @ ؐg?d<וx]:شX&X&[(e:vVc/ظX&X&[(]*`,c/qHyWzؼX&X&[(]*`,c/e1h3n;ySǤ~[HX&X&[(]*`,c/e1h3k5m7p:wF\[,ûX&X&[(]*`,c/e1h3k5m7p:sx@VᯇbGǿûX&X&[(]*`,c/e1h3k5m7p:sx@{C}EL]մhbĵíǿûX&X&[(]*`,c/e1h3k5m7p:sx@{C}EGIĆLÈQȺdzíǿûX&X&[(]*`,c/e1h3k5m7p:sx@{C}EGIĆLLjNĹ̹dzíǿûX&X&[(]*`,c/e1h3k5m7p:sx@{C}EGIĆLLjNǾп̹dzíǿûX&X&[(]*`,c/e1h3k5m7p:sx@{C}EGIĆLLjNп̹dzíǿûX&X&[(]*`,c/e1h3k5m7p:sx@{C}EGIĆLLjNп̹dzíǿûX&X&[(]*`,c/e1h3k5m7p:sx@{C}EGIĆLLjNп̹dzíǿûX&X&[(]*`,c/e1h3k5m7p:sx@{C}EGIĆLLjNп̹dzíǿûOKttV`,c/e1h3k5m7p:sx@{C}EGIĆLLjNп̹dzíǿû6:FvheceHk5m7p:sx@{C}EGIĆLLjNп̹dzíǿB-:*}2d-Z'Qy:oYh?r~FIĆLLjNп̹X+e4e4yB-:*}2d-Z'Qy!o7NGK2[=!kH({S.^4n=vBHпhl= e4e4e4yB-:*}2d-Z'Qy!o7NGK2[=!kH({S.^4i:i:i:ö[0e4e4e4e4e4yB-:*}2d-Z'Qy!o7NGK2[=!kH({S.^4i:je4e4e4e4e4e4e4yB-:*}2d-Z'Qy!o7NGK2[=!kH({S.e4@e4`e4e4e4e4yB.mmHHHHH2d2d(S|!o6OIK2[=!~:Hy2d3WtKJyqj1f_}voh~dz0{tle{dzxqjdzdz}vng~dzzs???!6h& (  @vBvBvBvBvBvBvBvBvBvBvBvBvBvBvBvBvBƹɼǻ˺ȹʹǼƾǿ½ǾƹôŹvBvBͻWXʺto˾ŵvBvBʹX\ͺqs̿vBvBͺ̻ɹ˻ʹϹʽƹvBvBVW˻qqͻøvBvBXYͺqs˻ǹvBvBɺ̺̿ͺǷvBvBXWtn̻˿ûvBvBWUtp̻˾ŽvBvBҿοŸvBvBXYĹvBvBWUǼvBvBǺvBvBƺvBvBvBvBvBvBvBvBvBvBvBvBvBvBvBvBvB( @ fwErDwDwDvCxCxEq?tBwFvCuArAvDtCuBvBv>uBvCxDvCuBuDtFy@pGsAsB_drAa{EzDzHyDHz@{E~H{F{FwG|FyCyD}D|B|AD~H{CGzDGvFFetBdfvCgϾοϺ˻̻̼ʾͻʻfuBg_uCf,1,'L(K)N̻˺hxG^]t@d*0*(M+N*L˾ʽ̻gs@_^r?f*-.(M*I)K˾н;dtC_]wCiν˾̽dy@`^yFdzvw.,+(M(J&PϿоѿfuCacwAaw{v+-,*M&L$HϾλcvCcdrBdvvy,(.(L&K#IппbvDbbo?]atBaczCexw{ol mhfhffgbuBbcv?dwwzm l o ffhhhdcvDcdwEb|ywm l k fhgefibxEaix;bcvC`du>e&*&+&)$)&(!)wx wm nl bs@`lv>g!(%(* +'&*wxzm mner?dly@e&$"("*,*($)uvwn n m fuAdcvCfguA`gvCc'+$'%',+*)+'fzBdbz@a%($+#(+**+)+ezBcdxAc!*&*%,+,.(&)dwBaftAfewBebtBi*("(#%-,,fwBfdwCg"'&( ()-(fvBdjy=b&(#*&*),*evCfbuFdeu>baxCcyD{F~D{G|IyCGG|FHuFExJGwGFuE~EwE~E{GGvE|EHhtA\lxDrCv?sAtCtEwBuBwCxDuDsBt@tAs?q?t?uAs>sAwDwDvAxAtFy=sAs@yGj!8BM86(   !Hn'Ho$Io$Hpvlzax$Hp&JpvJ-F"A$_4!g>%lH*];#Go$GovG?dl=l„¶v[&Hlvm6eu6dwϘeʕcɏ[ʻ}ȤhnuHȩxpwLrwu٬ҟtȏ[ȅR\-ץk.'aqZةqֳΓbݕd9ZfPnZGXkVة޴Ϟṗ7#=F1߾ibmԬֲ’}f $c_MôW۟wܺѾx];`. *syY~ur`nu*EHjU"K@`Qc;ol ]|l^zy[ʙ-s6Ǫ֐jӺ|!  ( @    %16999961%  ,:ZTR\VRWPKNF@I@:I@:NF@WPK\VRZTR:, '653d[VRNE@rSYg{nrrrrogzUWNF@[VR653d'/YUSNE@ZgkkmkkkkkkkkkZfOGAYUS/0[TPgLVa|ddddddcddcddddeUG\[TP1/[TP|^P}cey]]]]]]]]]]]]]]keeZUy[TP/ '[TPyZLvZvZraYzV|U~U{U{U{U{U{U{U{U{U{U{TlZ\\\\SMqZTO' [VTiSIrVpSpSpSbbPuNvNvNvNvNvNvNvNvNvNvMyuPUUUUUUXXQI^[VT ><:YNF@lRkLkLkLkLfMUcHqGpGpGpGpGpGpGpGpGrDTNNNNNNNNNTTNF@><:Y ]WT\LeEeEeEeEeEeEeEFfAi@k@j@j@j@j@j@m=xGGGGGGGGGGGGGGSO~]WS %NE@bE^=^=^=^=^=^=^=WK?]8e7d7d7d7d7d4uZ;??????????????GFNF@% ]YVhL?Y7Y7Y7Y7Y7Y7Y7Y7Y7EL5]1_1_1_1_/fl.999999999999999999JDa^YW]WT\GY7Y7Y7Y7Y7Y7Y7Y7Y7V:9X4^2`1_2`.nF9999999999999999999JG]WTWPKaGY7Y7Y7Y7Y7Y7Y7Y7Y7Y7U?7Z1_1_/hN799999999999999999999HGWPKNE@V@Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7HH1_0`a19999999999999999999999>>NE@H?9Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y74^4^99999999999999999999999999I@:H?9k̄k̄k̄k̄k̄k̄k̄k̄k̄k̄k̄k̄rіI<<<<<<<<<<<a\XOGB~~OGAa\Xhda>H?9H?9H?9gb__ZVXQLNF@I@:I@:NF@XQL_ZVgb_H?9H?9H?9??!  ( @    %16999961%  ,:ZTR\VRWPKNF@I@:I@:NF@WPK\VRZTR:, '653d[VRNE@rSYg{nrrrrogzUWNF@[VR653d'/YUSNE@ZgkkmkkkkkkkkkZfOGAYUS/0[TPgLVa|ddddddcddcddddeUG\[TP1/[TP|^P}cey]]]]]]]]]]]]]]keeZUy[TP/ '[TPyZLvZvZraYzV|U~U{U{U{U{U{U{U{U{U{U{TlZ\\\\SMqZTO' [VTiSIrVpSpSpSbbPuNvNvNvNvNvNvNvNvNvNvMyuPUUUUUUXXQI^[VT ><:YNF@lRkLkLkLkLfMUcHqGpGpGpGpGpGpGpGpGrDTNNNNNNNNNTTNF@><:Y ]WT\LeEeEeEeEeEeEeEFfAi@k@j@j@j@j@j@m=xGGGGGGGGGGGGGGSO~]WS %NE@bE^=^=^=^=^=^=^=WK?]8e7d7d7d7d7d4uZ;??????????????GFNF@% ]YVhL?Y7Y7Y7Y7Y7Y7Y7Y7Y7EL5]1_1_1_1_/fl.999999999999999999JDa^YW]WT\GY7Y7Y7Y7Y7Y7Y7Y7Y7V:9X4^2`1_2`.nF9999999999999999999JG]WTWPKaGY7Y7Y7Y7Y7Y7Y7Y7Y7Y7U?7Z1_1_/hN799999999999999999999HGWPKNE@V@Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7HH1_0`a19999999999999999999999>>NE@H?9Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y74^4^99999999999999999999999999I@:H?9k̄k̄k̄k̄k̄k̄k̄k̄k̄k̄k̄k̄rіI<<<<<<<<<<<a\XOGB~~OGAa\Xhda>H?9H?9H?9gb__ZVXQLNF@I@:I@:NF@XQL_ZVgb_H?9H?9H?9??!  ( @    %16999961%  ,:ZTR\VRWPKNF@I@:I@:NF@WPK\VRZTR:, '653d[VRNE@rSYg{nrrrrogzUWNF@[VR653d'/YUSNE@ZgkkmkkkkkkkkkZfOGAYUS/0[TPgLVa|ddddddcddcddddeUG\[TP1/[TP|^P}cey]]]]]]]]]]]]]]keeZUy[TP/ '[TPyZLvZvZraYzV|U~U{U{U{U{U{U{U{U{U{U{TlZ\\\\SMqZTO' [VTiSIrVpSpSpSbbPuNvNvNvNvNvNvNvNvNvNvMyuPUUUUUUXXQI^[VT ><:YNF@lRkLkLkLkLfMUcHqGpGpGpGpGpGpGpGpGrDTNNNNNNNNNTTNF@><:Y ]WT\LeEeEeEeEeEeEeEFfAi@k@j@j@j@j@j@m=xGGGGGGGGGGGGGGSO~]WS %NE@bE^=^=^=^=^=^=^=WK?]8e7d7d7d7d7d4uZ;??????????????GFNF@% ]YVhL?Y7Y7Y7Y7Y7Y7Y7Y7Y7EL5]1_1_1_1_/fl.999999999999999999JDa^YW]WT\GY7Y7Y7Y7Y7Y7Y7Y7Y7V:9X4^2`1_2`.nF9999999999999999999JG]WTWPKaGY7Y7Y7Y7Y7Y7Y7Y7Y7Y7U?7Z1_1_/hN799999999999999999999HGWPKNE@V@Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7HH1_0`a19999999999999999999999>>NE@H?9Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y74^4^99999999999999999999999999I@:H?9k̄k̄k̄k̄k̄k̄k̄k̄k̄k̄k̄k̄rіI<<<<<<<<<<<a\XOGB~~OGAa\Xhda>H?9H?9H?9gb__ZVXQLNF@I@:I@:NF@XQL_ZVgb_H?9H?9H?9??!  ( @ {OOOOONNNMMMMLML}L}L{KzLyLyKw}ya```_`````_````_`_a^Kwy~|zywvussqpnnmlibLxy~}{yyxvtsrqpommcLzz~|{zxvvtrqppncK{{}|{ywwutrqpdL|||{zywuusreL~|~|{zxvutfM~~|zywwgM}|zxiN~|{iN}kNlOnO|OO~}|{zzyxxwvvuoZLnc~{ueQvoyskYbPv`RvlZEbPjXww?!  ( @   xxxxxxxxxxxxxxxxxxxx®xyeye||ytl{et`nZiTxxSgRgQfQfQfQfQfQfQfxWq_}lʼnt͐t͐t͐t͐t͐<96yyyzazazzvqjzcs\lVePwhzWq_}`}fhhgv{wOgVp^}_}_}_}_}`|twC_Zt`~`~`~a~utyyuqizbs]mWhQuɷA\^zbbbixEzpD_d~ee`>vlswmpZyKchhStC}nVl]qUmk@zGVowHaimmmmmE~JmmmmmmmmeB]hwYmyɏtĊr‰opppINppopppmYrasPf̓xǎuČtstttst~KQiqussssp\uPgKcΕ|ʑyǎwčvŒvŒu‹u‹u‹u‹vŒPU}vËvŒu‹ayGbHa˒Γ|ɑ{ǐyŎyĎyčyĎyĎyĎyĎxÍyčTWyĎc|B^ĹH`}ǎЗ͔}Ȓ|ǐ|Ő|Ɛ{Ő{Ə|Ɛ|Ɛ{Ő|Ƒ{Ő|ŐX]A]÷Kd}ƎҘϕ̕~ȓ}ǒ~ǒ~Ǒ}Ǒ~ǒ~ǒ~ǒ}ƒ~ǒ~ǒ~ǒ~ƑT[u~XnĎ՜ӚқҞѡѢѢѢѢѢѢѢѢѢѢѢѢѢ]\UirhpݭޯXl`&]xxxxxxxxxxxxxxxxxxxxxxxef(^vv^_GG\]AAonfgzz!  ( @    $000000000000000000000000$ www<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<:FB>nB~zv333333333333333333333333333333333333333333333333333333333333333333333333333333331###########13333331'''''''''''##333333'&# #333333'&##### ###333333'&# #333333'&##333333'# #333333'  #%%# #####%%#333333'# #333333'##333333'%%%%%%%%%%# !! #333333'#- -**-#333333'# ,,,, #333333'#  #333333'  #   #333333'#  #333333'----------##333333'1###########1333333'333333333333''333333333333' 2 2 '333333333333'""""2 " 2"""""""""'333333333333'   '333333333333''333333333333''333333333333''333333333333''333333333333''3333333333331''''''''''''''''''133333333333333333333333333333333333333333( @ 0:::::::::::++:::::::::::?yuH?9H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9yu~zwF@::::::::::::::+ g&_ZrZO# $`~RKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKF~\|_aaO% RKFNAs_ggO' 8RKF.iWrlO- vRKF"b@rrO-RKF9Un0rrrO%:RKFPPjj-8`PPRKF~1`rrO|RKF~c?rr9FRKF~5)RKFRKFrqqjRKFRKF-8`-8`RKFRKFPCxRKFRKFPCxRKFRKFPCxRKFRKFPCxRKFRKFPCxRKFRKFPCxRKFRKFPCxRKFRKFPCxRKFRKFPCxRKFRKFPCxo]So]So]So]So]So]So]So]So]SRKFo]So]Sddd7RKFo]So]SgggFRKFo]So]Sfff<RKFo]So]SgggFRKFo]So]Sfff6RKFo]So]Sfff>RKFo]So]SgggC~RKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFo]SkkkD?!~ h(  XXX<<<<<<<<<<<<<<<<<<<<<<<<<<>>~zvrnn6JFFFFB>~zzJFFBBB         (  ~zwF@>>>>>>>>>>>>>>>>>>>>===>>>>>>>>>KKK<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< <<<<<< www<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>|xKD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>FKD>FFKD>FF5KD>F F5KD>FFFFFFFFFFFF###F5KD>F&&&&&&&&&&&&&&&F&KD>F***************jFKD>Fnnnnnnnnnnn///nFKD>FFFFFFFFFFFFq4qFKD>FuuFKD>FxFKD>FFKD>FKD>KD>KD>KD>KD>ynynynynynynynynynKD>ynynti`7KD>ynynwmcFKD>ynynuka<KD>ynynwmcFKD>ynynvka6KD>ynynvka>KD>ynynwlbC|xKD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>yn{pfD?!  ( @ hllllllllllllkkkllllllli*+ Ulu+ {[qn /_we~vs%4!^s!\q{q*:"   ! !# !  !0?,.+*.,*.,).,(-,).-)--)-08vupmmllmq(go(go(go(go(go(go(go(go(go(go(go(go(go(go(go(go9=93-(" (go(goNQKE@94.)#(go(goSVQKD>93.)"(go(go(go(go(go(go^\VQID>94-("(go(go&(goga[VPKD>93-)!(go(go09-(golga[UPID>93-((go(go8D7(goqlga[UPID>93-(go(goAMA(goxsnhb]WPID>93(go(goHWM(gopngb^XSUQID>9(go(goQaY(go(go(go(go(go(go(go(go(goYSLFA(go(goXkb^WRLE@94!(goF=84(go(gobvnhb]WQID>8*(go(go(go(goRf`YUPILUMGB='(go(go(go(go(go(go(go(go(go(goL[SMH.(go(goEC@='(go(go(go(go(go(go(go?!  ( @ +::::::::::::::::::::::::::::+qli3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(qli3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(ricricricricricricric3-(3-(ric3-(@83C3-(ric3-(A93=3-(ric3-(?7273-(ric3-(A93F3-(ric3-(@82<3-(ric3-(A93Fqli3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(~3-(A935?! hh f  0000^- hJ  nN00 %_( @bvBb6BrJvZ*nJ6j>rZ~N~jzvV6.jNjFzVV&fb>vRv ~R&^:f6fnBκrNrZ2jBR~zZ>~~^bb:^jVvVnZ6:VnFzZf>^6 vBrNvZ2jBR"~AQ7##B;*<A77##/T MEAL 7#/AAD 7##/AARK 7A ?A( 7A=%A>A9I.O2AW 65"I]4"=%NPX+5'] 26::::@53]]]P5:111]]]]]])115]]] 01 5VV]V[-SC]!,( @6\}, AVCLLLLP8LLubP LL{i^wTPLL}od{ZsOkEPLLLLzuj`xUpKhAa6P[4fopf}\uQmGe<[1}R%}N[4}vbyWqMg@{[<{[<{[<{[X0z[<ͻͻͻyri>ͻͻk[4i>Y+}OmAwW6ͻ~|[4sMsMsMS#sBc5]4 i>i>i>i>U$tA \:s[( @BNJZ³^1bfzvBrXfF&dO&&.rzfnFNd6~NvzVj~R&ZjBȮ:rR2*f:jjBZ6z^ R~z^>n~~vNZ*ʽʶZ.6>opz^f~zj{N"zJbξ&er^nRvR.\>ZkBn~z"^6*V'ʶl̺6^6zJz2rʲN~V2P. >JfnBrJMR~ZfvFzbRb:y2=R"bwV&Z>v~rZnvN&bjNl>.nzKvV]:~g*~Z:|3ªj~l: fV6bB"rJ"h:v~V*b:^2~frNV2 &r~6>ƶvZP*j>~_v_N\nJ&NfR"b6rZ2 vFRr~z~fz*.&r*zZnzR*®¶uJ`ʺβ>NnFTb>rRtBvzjnJ|NjFf>fBvRCCCCCCCCCCCCCCCCCCCCCCCCCCCCgRRRRllĮY%0?)LC2RoolQ>?)LvCI̝SRll(?)LCUѝZRlbj?)LC7ѝS bl0G?)Cuܫѝ̈́Rl4G?C/">ч R o44%/yaÄԄSRR440/@y"RRRRlll4jB^@ygRRRRllj .^'@"ggRRR0K.^'@g}T.AAwO'@Igf|AAAwO'@Ц|xtw홳O'@uuWʽq梾#w3O'yʽ+qq#~w3OK++qqxt#*w|+]]q #~c[w|ʁ+]]]q xt#:!E$Aeh]+_J #c!E{iJr 8J x#kN,Eixt#ckίP--Xi<酻 Ʌ#~ה5&9ip`Ji< ~c:!n`iJ:[FsXnPi;\ :[wٴ 6i1;HV xF\i<  9*[=i#~c:wd =;iiiiiiiiiiii$r1H??( @ +8EQ^jwj|'.?L>L  4= /lzn~%k|O\N\AMYk KZ?L)&_o1 l}j| &.&.  exP`q>o}j|[lg{L[3=awaw(Qbr Kp}k|4>3='/sL[r)Sdt[ X%q~ 7?j|(/i| g{fzL[dyo1<=K;I M. e67>5>j|4=3=Xjcx1;IY PedW6 qdW Mcdt[uI~pd6MX[q[t[x[zLߋ}p]MSRr]u]w]y[yY~Oߘ}o1MSAxgv^y_z]z\yYwUP|o%MM0xgxaza{a}^|\zXwTsNP|n1MM(v}pyc{c~c~a}^|[yWuQqLmGP{nOMM dwa|eeda~^{ZwUsOoJkEh@P{f[u_}ghfda~]zXvRrMnHjCf=b8PRt^{djigc`|[xUtPpKlFhAe;a6]1Pyfzcjlifc~^zXvSrNnIjDg>c9_4[/V)PpS{bt[t[w_ޘinliea}\yVuQqLmGiAec9[2wP(dBdF'iLz\>rS2}[8uPvPxn̲xV·ͻvfy]̲nȷxikDg?c:`4\/X*~R$rHa;P/ j̸~}y̲fƷ˻f=b7^2Z-V(R#zLnB]6O, [<±{̲_˾ȵtcvRi?Y+U&Q |LsDf;W0L(pVש̲zXȹͼŰ{j|YnF_3O yIrCi; ]2Q+M&Ƹ~̲tPôʸsatMe;T&tBj; `4V,O']9~̲oIkDg>c9_4X*T$P}LyGtBl; e4\/S'^9ǽ˿̲̲̲̲̲̲̲̲̲̲̲˱ȯªĶ??(0` BN±L[c8anWqBqN*L"&.JI^2vznvzX}N[ĮrMR2qgJdD jZ,l8zczrbO*hzm; "J"r^<&yJ ű`:mP.jBvX'^{^V&nHV2 vN#V*rjBrJZ4f}hV:~bB9̻V+gïzRiPz~dZ2̽ZM~ZrRmFCM, rb6 R$tEZj6>FrjJ5~j|6&r~Vj 2= ʶbzn~¾&R>Jj}w&N>~ƺ8W>"ȶjFvbr^:z^Bv^NZ^B&+f>Ͼ2ƶl>}~^zV2βrZxR.K&f6k,f>v^3`>5BJnJ&l.fvRbvFJwRʲW6r^.2vcªPnBZ6zR&X.jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjYYRRRRRRRR5+v8lH((i- `6yzr0jYRRRRRRRR5+vlH((i- `6yz0j=c)R1)RRR8lH(i- `6yzrj=<<RRRUQv8l((i- ``yzjRRRQ8lH((i- `6yj1RRR)H((i- `6jG1<<)RvH(i- `6jqGRRR)v((i- Hjqcc1RR)l((iZ_<R1RRUHZl{ҽd1%1<11RRRUl:dqYYRRRRRRRR5T:dYRRRRRRRR@ T::dqYYRRRRRRR^v@m. F> ::dYRRRRRRRR+_.FFg ::dYYRRRRRv@ԻFIg ::dYYRRR@ТIIII7g :dYY𤛻,III77g :dqYY^+{,,IIK77g :d,,kkK7g :ddY=9,kkk KEٱ7g :dd=q,kkWWW sKEUٱ7g :dd@,&&WW sKEUٱ7g dΝo,&&WW sKEEUٱ7gZ輨,&W sKE'Yj,&W KE'Jp#h##hh , sKKE''J~tI,&|CCC sKE'J~C&kkk&&|||C sE'b~N>X|CC||CC sK;VVbNTuS> ?XCC KVuuSCxp sKKEV$$B}Cex]?C ̏KE$[!!DDMuK"Ae?CW KEV[#WI\KsfA XCsKKE'uDpp" sя XꏏĎL *2ɳ3s"ƔAp?CEE''J~NSBMwnXCa3 X" ''J~>SMw֍2ɳƔxpXsK'JJ~>MwPn? a''J~>}/čeƔex "sEbJ~>}/P2naA]CK'~>}O/Pnp2ǫƔexX"f~>O2e2na?CsJ>4OhPnKEEKE'''>4OOn3p333e?(0`  '09CLU_hqz  )2;ENXajs}% ey 2< MZ:GQZdlu-$N\ M[L[q >J q AK@IS\fox5, Yj%-K[pbx1;.LU_hqz=4!4=h{Zk3<Xj1<Wi1;0;'Rajs|F='4=h{ 2<dycxbx{CcluNE-'.v[k@LL[2< KZKZEfnw[WN4 4=h{&-Yj2<Xj~  {XhpxgM_V:6>4=O\M[fz2<KZ1< $,&bgU^h_K&q}o}j|h{gzfzdy}*U  Fsixxxog^UL !E. KrZrGyyyxog^U/L8 5nWpXtYuIzzz߀wnf]Od:a7PzeMYu_xa~gjiigeb`}\{YxUuRsNpKmGjDh@e=c9`6^2Pe Ms_wa|ekkkigdb^|[yWwTtPqMoIlFiBg?e;b8`4]1Z-Pd;b7_4]0Y-V(S%}P!|M~OƬyZmid~cfhjoqpmjgc`}\{YxUuRsNpKlFiCf?dW9T5S3Q2Q0Q/ T0 kDe=pInT̲qųzkd`~]{YvRsOpKnHkDhAf=c:`6[1|T+oJ$a?W8dHhx\~`B{]=mKxW~[xSsMyo̲tɸų|n_}[zXwTrMoJmFjCg?eT5L/ítmf_|Xx^̲~uyWvStP«ýŴɵt~]}{̲qξɹıwlwTsNpKkDh@f=c9a6^2[/Y+V(R#xLmD`:S2J+ _A%̾Ͻí~~t̲l³̻ƴzpaqKlFg?e;b8`4]1Z-X*U&R#}OvHk@]7R/ J)G'ŵȴw̲hŷξɷ~sh~\mEd:a7_3\/Y,W(T%Q!OzJqCg<Z3 O+I'H&ʻ}̲cɻ²̻a6^2[.X+V'S$P }MzJtDk>`6 U/L)H&`@|̲^ƷϾɷįpe}ZtNj@]1W)U&R"~N{LxHsCk>c7 Y0O*K'J%о̲{Yʽóͻdzuj]wRnFc9Y+Q!}M{KwFqBl= c7 [1S,N(K%K$ʻ̲wTǹʸŰ{nc{VqKh>^1S${JvFrAk< d7 ^2W-R*M%I"ƪ̲sO̿Ĵμȴ¬ti\vPlCb6W(|LsAm= g8a3\/U*P&L#jRͿ̲pKmGjDh@eX0z[<ͻͻͻ`=7i>ͻͻc[4i>Y+}OmAwW6ͻ{fQ[4sMsMsMS#sBc5]4 ~:i>i>i>i>U$tA \:s[9( @ +8EQ^jwj|'.?L>L  4= /lzn~%k|O\N\AMYk KZ?L)&_o1 l}j| &.&.  exP`q>o}j|[lg{L[3=awaw(Qbr Kp}k|4>3='/sL[r)Sdt[ X%q~ 7?j|(/i| g{fzL[dyo1<=K;I M e67>5>j|4=3=Xjcx1;IY PedW6 qdW Mcdt[uI~pd6MX[q[t[x[zL}p]MSRr]u]w]y[yY~O}o1MSAxgv^y_z]z\yYwUP|o%MM0xgxaza{a}^|\zXwTsNP|n1MM(v}pyc{c~c~a}^|[yWuQqLmGP{nOMM dwa|eeda~^{ZwUsOoJkEh@P{f[u_}ghfda~]zXvRrMnHjCf=b8PRt^{djigc`|[xUtPpKlFhAe;a6]1Pyfzcjlifc~^zXvSrNnIjDg>c9_4[/V)PpS{bt[t[w_inliea}\yVuQqLmGiAec9[2wP(dBdF'iLz\>rS2}[8uPvPc?G̲xV·ͻvfwS̲nȷxikDg?c:`4\/X*~R$rHa;P/ j̸~kN&̲fƷ˻f=b7^2Z-V(R#zLnB]6O, [<±tk̲_˾ȵtcvRi?Y+U&Q |LsDf;W0L(pV̲zXȹͼŰ{j|YnF_3O yIrCi; ]2Q+M&Ƹȵٍzf̲tPôʸsatMe;T&tBj; `4V,O']9Ĵyj̲oIkDg>c9_4X*T$P}LyGtBl; e4\/S'^9ɾ7̲̲̲̲̲̲̲̲̲̲̲˱ȯªŷ˻??(0` %  '09CLU_hqz  )2;ENXajs}% ey 2< MZ:GQZdlu-$N\ M[L[q >J q AK@IS\fox5, Yj%-K[pbx1;.LU_hqz=4!4=h{Zk3<Xj1<Wi1;0;'Rajs|F='4=h{ 2<dycxbx{CcluNE-'.v[k@LL[2< KZKZEfnw[WN4 4=h{&-Yj2<Xj~  {XhpxgM_V:6>4=O\M[fz2<KZ1< $,&bgUEh_K&q}o}j|h{gzfzdy}*U  Fsiog^UL !E. KrZrGxog^U/L8 5nWpXtYuIwnf]Od:a7PzeMYu_xa~gjiigeb`}\{YxUuRsNpKmGjDh@e=c9`6^2Pe Ms_wa|ekkkigdb^|[yWwTtPqMoIlFiBg?e;b8`4]1Z-Pd;b7_4]0Y-V(S%}P!|M~OƬyZmid~cfhjoqpmjgc`}\{YxUuRsNpKlFiCf?dW9T5S3Q2Q0Q/ T0 kDe=pIe=̲qųzkd`~]{YvRsOpKnHkDhAf=c:`6[1|T+oJ$a?W8dHhx\~`B{]=mKxW~[xSsMeAE̲tɸų|n_}[zXwTrMoJmFjCg?eT5L/ítmf_|XtO̲~uyWvStPýŴɵt~[w\A̲qξɹıwlwTsNpKkDh@f=c9a6^2[/Y+V(R#xLmD`:S2J+ _A%̾Ͻí~{[V̲l³̻ƴzpaqKlFg?e;b8`4]1Z-X*U&R#}OvHk@]7R/ J)G'ŵȴr̲hŷξɷ~sh~\mEd:a7_3\/Y,W(T%Q!OzJqCg<Z3 O+I'H&ʻԊrY̲cɻ²̻a6^2[.X+V'S$P }MzJtDk>`6 U/L)H&`@Įo5̲^ƷϾɷįpe}ZtNj@]1W)U&R"~N{LxHsCk>c7 Y0O*K'J%оd̲{Yʽóͻdzuj]wRnFc9Y+Q!}M{KwFqBl= c7 [1S,N(K%K$ʻ̲wTǹʸŰ{nc{VqKh>^1S${JvFrAk< d7 ^2W-R*M%I"̲sO̿Ĵμȴ¬ti\vPlCb6W(|LsAm= g8a3\/U*P&L#jRͿǵ̲pKmGjDh@enYt????????????????????????!  ( @    %16999961%  ,:ZTR\VRWPKNF@I@:I@:NF@WPK\VRZTR:, '653d[VRNE@rSYg{nrrrrogzUWNF@[VR653d'/YUSNE@ZgkkmkkkkkkkkkZfOGAYUS/0[TPgLVa|ddddddcddcddddeUG\[TP1/[TP|^P}cey]]]]]]]]]]]]]]keeZUy[TP/ '[TPyZLvZvZraYzV|U~U{U{U{U{U{U{U{U{U{U{TlZ\\\\SMqZTO' [VTiSIrVpSpSpSbbPuNvNvNvNvNvNvNvNvNvNvMyuPUUUUUUXXQI^[VT ><:YNF@lRkLkLkLkLfMUcHqGpGpGpGpGpGpGpGpGrDTNNNNNNNNNTTNF@><:Y ]WT\LeEeEeEeEeEeEeEFfAi@k@j@j@j@j@j@m=xGGGGGGGGGGGGGGSO~]WS %NE@bE^=^=^=^=^=^=^=WK?]8e7d7d7d7d7d4uZ;??????????????GFNF@% ]YVhL?Y7Y7Y7Y7Y7Y7Y7Y7Y7EL5]1_1_1_1_/fl.999999999999999999JDa^YW]WT\GY7Y7Y7Y7Y7Y7Y7Y7Y7V:9X4^2`1_2`.nF9999999999999999999JG]WTWPKaGY7Y7Y7Y7Y7Y7Y7Y7Y7Y7U?7Z1_1_/hN799999999999999999999HGWPKNE@V@Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7HH1_0`a19999999999999999999999>>NE@H?9Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y74^4^99999999999999999999999999I@:H?9k̄k̄k̄k̄k̄k̄k̄k̄k̄k̄k̄k̄rіI<<<<<<<<<<<a\XOGB~~OGAa\Xhda>H?9H?9H?9gb__ZVXQLNF@I@:I@:NF@XQL_ZVgb_H?9H?9H?9??!  ( @ 2::::::::::::::::::2 .*(eRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKF%#!^ H?9RKFRKF+(&j H?9RKFRKF'%"b H?9RKFRKF+(&jH?9RKFRKF%#!^ H?9RKFRKF(%#d H?9RKFRKF*'%h H?9RKFRKF+(&kH?9RKFRKFRKFRKFRKFRKFRKFRKF.+(eH?9RKFRKFH?9RKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKF~H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9D?;DH?9H?9A=9CB=:5H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9C>:<?! hh f  0000^- hJ  nN00 %_( @bvBb6BrJvZ*nJ6j>rZ~N~jzvV6.jNjFzVV&fb>vRv ~R&^:f6fnBκrNrZ2jBR~zZ>~~^bb:^jVvVnZ6:VnFzZf>^6 vBrNvZ2jBR"~AQ7##B;*<A77##/T MEAL 7#/AAD 7##/AARK 7A ?A( 7A=%A>A9I.O2AW 65"I]4"=%NPX+5'] 26::::@53]]]P5:111]]]]]])115]]] 01 5VV]V[-SC]!,( @6\}, AVCLLLLP8LLubP LL{i^wTPLL}od{ZsOkEPLLLLzuj`xUpKhAa6P[4fopf}\uQmGe<[1}R%}N[4}vbyWqMg@{[<{[<{[<{[X0z[<ͻͻͻyri>ͻͻk[4i>Y+}OmAwW6ͻ~|[4sMsMsMS#sBc5]4 i>i>i>i>U$tA \:s[( @BNJZ³^1bfzvBrXfF&dO&&.rzfnFNd6~NvzVj~R&ZjBȮ:rR2*f:jjBZ6z^ R~z^>n~~vNZ*ʽʶZ.6>opz^f~zj{N"zJbξ&er^nRvR.\>ZkBn~z"^6*V'ʶl̺6^6zJz2rʲN~V2P. >JfnBrJMR~ZfvFzbRb:y2=R"bwV&Z>v~rZnvN&bjNl>.nzKvV]:~g*~Z:|3ªj~l: fV6bB"rJ"h:v~V*b:^2~frNV2 &r~6>ƶvZP*j>~_v_N\nJ&NfR"b6rZ2 vFRr~z~fz*.&r*zZnzR*®¶uJ`ʺβ>NnFTb>rRtBvzjnJ|NjFf>fBvRCCCCCCCCCCCCCCCCCCCCCCCCCCCCgRRRRllĮY%0?)LC2RoolQ>?)LvCI̝SRll(?)LCUѝZRlbj?)LC7ѝS bl0G?)Cuܫѝ̈́Rl4G?C/">ч R o44%/yaÄԄSRR440/@y"RRRRlll4jB^@ygRRRRllj .^'@"ggRRR0K.^'@g}T.AAwO'@Igf|AAAwO'@Ц|xtw홳O'@uuWʽq梾#w3O'yʽ+qq#~w3OK++qqxt#*w|+]]q #~c[w|ʁ+]]]q xt#:!E$Aeh]+_J #c!E{iJr 8J x#kN,Eixt#ckίP--Xi<酻 Ʌ#~ה5&9ip`Ji< ~c:!n`iJ:[FsXnPi;\ :[wٴ 6i1;HV xF\i<  9*[=i#~c:wd =;iiiiiiiiiiii$r1H??( @ +8EQ^jwj|'.?L>L  4= /lzn~%k|O\N\AMYk KZ?L)&_o1 l}j| &.&.  exP`q>o}j|[lg{L[3=awaw(Qbr Kp}k|4>3='/sL[r)Sdt[ X%q~ 7?j|(/i| g{fzL[dyo1<=K;I M. e67>5>j|4=3=Xjcx1;IY PedW6 qdW Mcdt[uI~pd6MX[q[t[x[zLߋ}p]MSRr]u]w]y[yY~Oߘ}o1MSAxgv^y_z]z\yYwUP|o%MM0xgxaza{a}^|\zXwTsNP|n1MM(v}pyc{c~c~a}^|[yWuQqLmGP{nOMM dwa|eeda~^{ZwUsOoJkEh@P{f[u_}ghfda~]zXvRrMnHjCf=b8PRt^{djigc`|[xUtPpKlFhAe;a6]1Pyfzcjlifc~^zXvSrNnIjDg>c9_4[/V)PpS{bt[t[w_ޘinliea}\yVuQqLmGiAec9[2wP(dBdF'iLz\>rS2}[8uPvPxn̲xV·ͻvfy]̲nȷxikDg?c:`4\/X*~R$rHa;P/ j̸~}y̲fƷ˻f=b7^2Z-V(R#zLnB]6O, [<±{̲_˾ȵtcvRi?Y+U&Q |LsDf;W0L(pVש̲zXȹͼŰ{j|YnF_3O yIrCi; ]2Q+M&Ƹ~̲tPôʸsatMe;T&tBj; `4V,O']9~̲oIkDg>c9_4X*T$P}LyGtBl; e4\/S'^9ǽ˿̲̲̲̲̲̲̲̲̲̲̲˱ȯªĶ??(0` BN±L[c8anWqBqN*L"&.JI^2vznvzX}N[ĮrMR2qgJdD jZ,l8zczrbO*hzm; "J"r^<&yJ ű`:mP.jBvX'^{^V&nHV2 vN#V*rjBrJZ4f}hV:~bB9̻V+gïzRiPz~dZ2̽ZM~ZrRmFCM, rb6 R$tEZj6>FrjJ5~j|6&r~Vj 2= ʶbzn~¾&R>Jj}w&N>~ƺ8W>"ȶjFvbr^:z^Bv^NZ^B&+f>Ͼ2ƶl>}~^zV2βrZxR.K&f6k,f>v^3`>5BJnJ&l.fvRbvFJwRʲW6r^.2vcªPnBZ6zR&X.jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjYYRRRRRRRR5+v8lH((i- `6yzr0jYRRRRRRRR5+vlH((i- `6yz0j=c)R1)RRR8lH(i- `6yzrj=<<RRRUQv8l((i- ``yzjRRRQ8lH((i- `6yj1RRR)H((i- `6jG1<<)RvH(i- `6jqGRRR)v((i- Hjqcc1RR)l((iZ_<R1RRUHZl{ҽd1%1<11RRRUl:dqYYRRRRRRRR5T:dYRRRRRRRR@ T::dqYYRRRRRRR^v@m. F> ::dYRRRRRRRR+_.FFg ::dYYRRRRRv@ԻFIg ::dYYRRR@ТIIII7g :dYY𤛻,III77g :dqYY^+{,,IIK77g :d,,kkK7g :ddY=9,kkk KEٱ7g :dd=q,kkWWW sKEUٱ7g :dd@,&&WW sKEUٱ7g dΝo,&&WW sKEEUٱ7gZ輨,&W sKE'Yj,&W KE'Jp#h##hh , sKKE''J~tI,&|CCC sKE'J~C&kkk&&|||C sE'b~N>X|CC||CC sK;VVbNTuS> ?XCC KVuuSCxp sKKEV$$B}Cex]?C ̏KE$[!!DDMuK"Ae?CW KEV[#WI\KsfA XCsKKE'uDpp" sя XꏏĎL *2ɳ3s"ƔAp?CEE''J~NSBMwnXCa3 X" ''J~>SMw֍2ɳƔxpXsK'JJ~>MwPn? a''J~>}/čeƔex "sEbJ~>}/P2naA]CK'~>}O/Pnp2ǫƔexX"f~>O2e2na?CsJ>4OhPnKEEKE'''>4OOn3p333e?(0`  '09CLU_hqz  )2;ENXajs}% ey 2< MZ:GQZdlu-$N\ M[L[q >J q AK@IS\fox5, Yj%-K[pbx1;.LU_hqz=4!4=h{Zk3<Xj1<Wi1;0;'Rajs|F='4=h{ 2<dycxbx{CcluNE-'.v[k@LL[2< KZKZEfnw[WN4 4=h{&-Yj2<Xj~  {XhpxgM_V:6>4=O\M[fz2<KZ1< $,&bgU^h_K&q}o}j|h{gzfzdy}*U  Fsixxxog^UL !E. KrZrGyyyxog^U/L8 5nWpXtYuIzzz߀wnf]Od:a7PzeMYu_xa~gjiigeb`}\{YxUuRsNpKmGjDh@e=c9`6^2Pe Ms_wa|ekkkigdb^|[yWwTtPqMoIlFiBg?e;b8`4]1Z-Pd;b7_4]0Y-V(S%}P!|M~OƬyZmid~cfhjoqpmjgc`}\{YxUuRsNpKlFiCf?dW9T5S3Q2Q0Q/ T0 kDe=pInT̲qųzkd`~]{YvRsOpKnHkDhAf=c:`6[1|T+oJ$a?W8dHhx\~`B{]=mKxW~[xSsMyo̲tɸų|n_}[zXwTrMoJmFjCg?eT5L/ítmf_|Xx^̲~uyWvStP«ýŴɵt~]}{̲qξɹıwlwTsNpKkDh@f=c9a6^2[/Y+V(R#xLmD`:S2J+ _A%̾Ͻí~~t̲l³̻ƴzpaqKlFg?e;b8`4]1Z-X*U&R#}OvHk@]7R/ J)G'ŵȴw̲hŷξɷ~sh~\mEd:a7_3\/Y,W(T%Q!OzJqCg<Z3 O+I'H&ʻ}̲cɻ²̻a6^2[.X+V'S$P }MzJtDk>`6 U/L)H&`@|̲^ƷϾɷįpe}ZtNj@]1W)U&R"~N{LxHsCk>c7 Y0O*K'J%о̲{Yʽóͻdzuj]wRnFc9Y+Q!}M{KwFqBl= c7 [1S,N(K%K$ʻ̲wTǹʸŰ{nc{VqKh>^1S${JvFrAk< d7 ^2W-R*M%I"ƪ̲sO̿Ĵμȴ¬ti\vPlCb6W(|LsAm= g8a3\/U*P&L#jRͿ̲pKmGjDh@eX0z[<ͻͻͻ`=7i>ͻͻc[4i>Y+}OmAwW6ͻ{fQ[4sMsMsMS#sBc5]4 ~:i>i>i>i>U$tA \:s[9( @ +8EQ^jwj|'.?L>L  4= /lzn~%k|O\N\AMYk KZ?L)&_o1 l}j| &.&.  exP`q>o}j|[lg{L[3=awaw(Qbr Kp}k|4>3='/sL[r)Sdt[ X%q~ 7?j|(/i| g{fzL[dyo1<=K;I M e67>5>j|4=3=Xjcx1;IY PedW6 qdW Mcdt[uI~pd6MX[q[t[x[zL}p]MSRr]u]w]y[yY~O}o1MSAxgv^y_z]z\yYwUP|o%MM0xgxaza{a}^|\zXwTsNP|n1MM(v}pyc{c~c~a}^|[yWuQqLmGP{nOMM dwa|eeda~^{ZwUsOoJkEh@P{f[u_}ghfda~]zXvRrMnHjCf=b8PRt^{djigc`|[xUtPpKlFhAe;a6]1Pyfzcjlifc~^zXvSrNnIjDg>c9_4[/V)PpS{bt[t[w_inliea}\yVuQqLmGiAec9[2wP(dBdF'iLz\>rS2}[8uPvPc?G̲xV·ͻvfwS̲nȷxikDg?c:`4\/X*~R$rHa;P/ j̸~kN&̲fƷ˻f=b7^2Z-V(R#zLnB]6O, [<±tk̲_˾ȵtcvRi?Y+U&Q |LsDf;W0L(pV̲zXȹͼŰ{j|YnF_3O yIrCi; ]2Q+M&Ƹȵٍzf̲tPôʸsatMe;T&tBj; `4V,O']9Ĵyj̲oIkDg>c9_4X*T$P}LyGtBl; e4\/S'^9ɾ7̲̲̲̲̲̲̲̲̲̲̲˱ȯªŷ˻??(0` %  '09CLU_hqz  )2;ENXajs}% ey 2< MZ:GQZdlu-$N\ M[L[q >J q AK@IS\fox5, Yj%-K[pbx1;.LU_hqz=4!4=h{Zk3<Xj1<Wi1;0;'Rajs|F='4=h{ 2<dycxbx{CcluNE-'.v[k@LL[2< KZKZEfnw[WN4 4=h{&-Yj2<Xj~  {XhpxgM_V:6>4=O\M[fz2<KZ1< $,&bgUEh_K&q}o}j|h{gzfzdy}*U  Fsiog^UL !E. KrZrGxog^U/L8 5nWpXtYuIwnf]Od:a7PzeMYu_xa~gjiigeb`}\{YxUuRsNpKmGjDh@e=c9`6^2Pe Ms_wa|ekkkigdb^|[yWwTtPqMoIlFiBg?e;b8`4]1Z-Pd;b7_4]0Y-V(S%}P!|M~OƬyZmid~cfhjoqpmjgc`}\{YxUuRsNpKlFiCf?dW9T5S3Q2Q0Q/ T0 kDe=pIe=̲qųzkd`~]{YvRsOpKnHkDhAf=c:`6[1|T+oJ$a?W8dHhx\~`B{]=mKxW~[xSsMeAE̲tɸų|n_}[zXwTrMoJmFjCg?eT5L/ítmf_|XtO̲~uyWvStPýŴɵt~[w\A̲qξɹıwlwTsNpKkDh@f=c9a6^2[/Y+V(R#xLmD`:S2J+ _A%̾Ͻí~{[V̲l³̻ƴzpaqKlFg?e;b8`4]1Z-X*U&R#}OvHk@]7R/ J)G'ŵȴr̲hŷξɷ~sh~\mEd:a7_3\/Y,W(T%Q!OzJqCg<Z3 O+I'H&ʻԊrY̲cɻ²̻a6^2[.X+V'S$P }MzJtDk>`6 U/L)H&`@Įo5̲^ƷϾɷįpe}ZtNj@]1W)U&R"~N{LxHsCk>c7 Y0O*K'J%оd̲{Yʽóͻdzuj]wRnFc9Y+Q!}M{KwFqBl= c7 [1S,N(K%K$ʻ̲wTǹʸŰ{nc{VqKh>^1S${JvFrAk< d7 ^2W-R*M%I"̲sO̿Ĵμȴ¬ti\vPlCb6W(|LsAm= g8a3\/U*P&L#jRͿǵ̲pKmGjDh@e<:YNF@lRkLkLkLkLfMUcHqGpGpGpGpGpGpGpGpGrDTNNNNNNNNNTTNF@><:Y ]WT\LeEeEeEeEeEeEeEFfAi@k@j@j@j@j@j@m=xGGGGGGGGGGGGGGSO~]WS %NE@bE^=^=^=^=^=^=^=WK?]8e7d7d7d7d7d4uZ;??????????????GFNF@% ]YVhL?Y7Y7Y7Y7Y7Y7Y7Y7Y7EL5]1_1_1_1_/fl.999999999999999999JDa^YW]WT\GY7Y7Y7Y7Y7Y7Y7Y7Y7V:9X4^2`1_2`.nF9999999999999999999JG]WTWPKaGY7Y7Y7Y7Y7Y7Y7Y7Y7Y7U?7Z1_1_/hN799999999999999999999HGWPKNE@V@Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7HH1_0`a19999999999999999999999>>NE@H?9Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y74^4^99999999999999999999999999I@:H?9k̄k̄k̄k̄k̄k̄k̄k̄k̄k̄k̄k̄rіI<<<<<<<<<<<a\XOGB~~OGAa\Xhda>H?9H?9H?9gb__ZVXQLNF@I@:I@:NF@XQL_ZVgb_H?9H?9H?9??!  ( @   $0000000000000000$ $kk$00 $qli3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(qliT$ $k3-(3-(k$ $00T3-(3-(T00$$kH?9H?93-(3-(H?9H?9k0H?9H?93-(3-(H?9H?9qli3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(qli3-(qd[qd[qd[qd[^RKRHBRHB[PHqd[qd[qd[qd[3-(3-(qd[qd[qd[qd[obYPF?3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(OE>l`Wqd[qd[qd[qd[3-(3-(qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[3-(3-(qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[3-(3-(3-(3-(3-(3-(ýý3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(^VPI@:I@:I@:I@:I@:I@:I@:I@:I@:JA;`XR3-(3-(_VQha\3-(k3-({tpogc3-($qli3-(3-(3-(3-(3-(3-(JA;I@:H?9I@:3-(3-(3-(3-(3-(3-(qliH?9H?93-(3-(H?9H?9k$H?9H?93-(3-(H?9H?9$ H?9H?93-(3-(H?9H?93-(3-(03-(3-(k$3-(3-($ qli3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(qli!  ( @    %16999961%  ,:ZTR\VRWPKNF@I@:I@:NF@WPK\VRZTR:, '653d[VRNE@rSYg{nrrrrogzUWNF@[VR653d'/YUSNE@ZgkkmkkkkkkkkkZfOGAYUS/0[TPgLVa|ddddddcddcddddeUG\[TP1/[TP|^P}cey]]]]]]]]]]]]]]keeZUy[TP/ '[TPyZLvZvZraYzV|U~U{U{U{U{U{U{U{U{U{U{TlZ\\\\SMqZTO' [VTiSIrVpSpSpSbbPuNvNvNvNvNvNvNvNvNvNvMyuPUUUUUUXXQI^[VT ><:YNF@lRkLkLkLkLfMUcHqGpGpGpGpGpGpGpGpGrDTNNNNNNNNNTTNF@><:Y ]WT\LeEeEeEeEeEeEeEFfAi@k@j@j@j@j@j@m=xGGGGGGGGGGGGGGSO~]WS %NE@bE^=^=^=^=^=^=^=WK?]8e7d7d7d7d7d4uZ;??????????????GFNF@% ]YVhL?Y7Y7Y7Y7Y7Y7Y7Y7Y7EL5]1_1_1_1_/fl.999999999999999999JDa^YW]WT\GY7Y7Y7Y7Y7Y7Y7Y7Y7V:9X4^2`1_2`.nF9999999999999999999JG]WTWPKaGY7Y7Y7Y7Y7Y7Y7Y7Y7Y7U?7Z1_1_/hN799999999999999999999HGWPKNE@V@Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7HH1_0`a19999999999999999999999>>NE@H?9Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y7Y74^4^99999999999999999999999999I@:H?9k̄k̄k̄k̄k̄k̄k̄k̄k̄k̄k̄k̄rіI<<<<<<<<<<<a\XOGB~~OGAa\Xhda>H?9H?9H?9gb__ZVXQLNF@I@:I@:NF@XQL_ZVgb_H?9H?9H?9??!  ( @   -59::4% O'Lz'Lz'Lz'Lz'Lz'Lz'Lz 91"[+:::: C)q!*K M"X%S'Lz%5Y!)H+t,333333333333333333333#8ZZ Y%R)Jv*Ag&.L/08"333Hz_!Z&R*Is)Ah#)G$+?333]WSGA=GA=\VR[UQGA=GA=rlhhb^GA=OF@HB>HB>HB>HB>HB>GA=F@KD>KD>KD>KD>MDMD<~~~MD<+?KD>rrrrMD<|||||||||||MD<"KD>KD>KD>rrrrMD<{{{MD<+::?KD>KD>KD>rrrrMDB<7B<7B<7B<7B<7MDMD|nMDKD>KD>KD>KD>KD>KD>KD>e[RKD>KD>KD>KD>KD>KD>KD>MF@g]TKD>KD>e[Re[RKD>KD>ynwlbKD>|xMF@MF@MF@MF@MF@MF@MF@KD>KD>KD>KD>KD>KD>KD>KD>KD>|xKD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>|xKD>KD>KD>KD>|xKD>KD>KD>KD>KD>KD>|xKD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>|x???!  ( @ 0:+5FEDFED@??+::::::::::::::.5FED333>>>FED|xKD>KD>KD>KD>KD>D?;KD>LE?E@>>yyyFED"KD>PPP======DDC///FED333>>>xxxFED+?KD>rrrrrrIHFmlkbbb>>>>>>xxxFED"KD>KD>KD>rrrrryIGE>>>FED+::?KD>KD>KD>rrrrrƺmljbba000=,{wsB<7B<7B<7B<7B<7IBB<7B<7B<7B<7B<7B<7<<<<<LLKmlhɻµkjfLLKKD>KD>MLL======MMLKD>KD>KD>KD>KD>KD>KD>KD>KD>KD>e[RKD>KD>KD>KD>KD>KD>KD>KD>e[RKD>KD>e[Re[RKD>KD>ynynKD>|xMF@MF@MF@MF@MF@MF@MF@KD>KD>MF@LE?LE?LE?LE?LE?MF@|xKD>KD>KD>JC=KD>KD>KD>KD>KD>JC=KD>KD>|xKD>KD>JC=KD>|xKD>JC=|xKD>JC=KD>KC=|xKD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>|x!$9GIF89a "CF/Om3,2g.Z\7nQQQq!P$FS;llt|>l/Jf"M~pf=0KMUb5EVQarY}Zg~apJJJAAA簱{0x/Vm %H5cDqA} (8#E)O d{vydkr-DZ+w}"k)P2u-\YYZcF4b.X|GYk999Bt&#-iJJRQ#@BkM~ 0Q2]듇;DM\[e19z#8+Q1pY@JYbJ_ 񦧧'ctovBmZj(i'EGBH*NR})q9f|~W 5 :b9}518#Y7V\ht~B{,_=_}%Lrd^bƭ )L[!@)))0Y0`rw|)K +,X1sMBx 3]s{@p7t0E]J].TuSHMZBk9\d8! XMP DataXMP Adobe Fireworks CS4 PR 2008-04-29T16:19:50Z 2008-04-29T22:13:44Z image/gif ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<:9876543210/.-,+*)('&%$#"!  !, af \4 #IW~DÍg $ ;$5%ɜԲrA@Q°cΣ;#% D fX$]HD/QE-V-CVuGDX AƌN8q:A˄DډÁ*:9vla3aA2E X# V^ՠvMɴmgͅ3 8u ᭩ 3qeYv!HIУ~n{d9F΅&H j}uuE%5!Ȃ `ܖ^ze{,wJ$9t0!G-{lh^,0‡r1DlXG2a/fdu&D{EH2 *†%eJ΁ "᠃#B+3pݗ&1!l ;YJ=\iΩd H-sgw$Q exIuz`@pB'@0 0p) ) xJ`:CE`@yh F  Ƚ 2bF @ wAگyB`Ppvd0ŤpB&3Ƞ2p1T 0hĨk8kvLl`Wqd[qd[qd[qd[3-(3-(qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[3-(3-(qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[qd[3-(3-(3-(3-(3-(3-(ýý3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(^VPI@:I@:I@:I@:I@:I@:I@:I@:I@:JA;`XR3-(3-(_VQha\3-(k3-({tpogc3-($qli3-(3-(3-(3-(3-(3-(JA;I@:H?9I@:3-(3-(3-(3-(3-(3-(qliH?9H?93-(3-(H?9H?9k$H?9H?93-(3-(H?9H?9$ H?9H?93-(3-(H?9H?93-(3-(03-(3-(k$3-(3-($ qli3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(qli!  ( @ +0FF5+::::::::::::::0"FvF5|xKD>KD>KD>KD>KD>D?;KD>LE?E@FFFFFFFFvvvF5+?KD>rrrrrrqqqFvvvvvvvvvvvF&"KD>KD>KD>rrrrrrrrrFvvvvvvvvvvvvF+::?KD>KD>KD>rrrrrrrrrFvvvvvvvvvvvF{wsB<7B<7B<7B<7B<7IBB<7B<7B<7B<7B<7B<7B<7B<7B<7B<7B<7B<7B<7B;6KD>uj`wlbFvFB<7wlbwlbwlbwlbwlbwlbwlbwlbwlbwlbwlbwlbwlbwlbwlbwlbwlbwlbwlbwlbwlbwlbwlbFFB<7wlbwlbwlbwlbwlbwlbwlbwlbwlbwlbwlbwlbwlbwlcwlcwlcwlcwlcwlcwlcwlcwlcwlcB<7B<7KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>e[RKD>KD>KD>KD>KD>KD>KD>KD>e[RKD>KD>e[Re[RKD>KD>ynynKD>|xMF@MF@MF@MF@MF@MF@MF@KD>KD>MF@LE?LE?LE?LE?LE?MF@|xKD>KD>KD>JC=KD>KD>KD>KD>KD>JC=KD>KD>|xKD>KD>JC=KD>|xKD>JC=|xKD>JC=KD>KC=|xKD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>|x!  ( @ !2:2 #6 fMJG`^]MIF e4$ 1;+++FDCQPO^\[MJH***E( "3XIECDCBmkkronSPO<;;O3" & <&%%tGDBRPOHGFIFE'&&v5&B/..FCA][YXVUFDC///BDA@jgexusEBACA@CA@CA@CA@CA@CA@CA@_]\CA@sx1tPF-vV9Yx2uʿ*CA@f]W:Y( G.w_`^jK/CA@p$]nL,tP_BNS:pN7qrpjqg,(@CA@v0b@b@eFdScHcz$qA,,)z"8g(5 CA@r^E>@=>{$dCA@]\hqwTb?¬ sNNo3-M;?CA@^iw+nUvI7J¦T/TصƫYjB-l}γaԼlվpѺn}Ο mͣ? QK8CA@^k|#5@ |վo{̃χʄȏ >̱`ȬXHCA@ar,>I k|Љ֒ۙܚ̋GwѻlѷdħSCA@f x2FP ͆ؕɧ b׳ԿsԼkʯ[DBAGDBK{"5HçU }ьߟ(bĶ ½xLJê[766<;;VGCBCA@GCB̺{<>N¦T9+^Oόަ˓ %˖V877=<<`EBAA@?GCB]G^$*пzS8ܴŌC/544 =</ƄݦؗƁiرt5 }b?ħSεbx ՓܚՐȀәGnHHʯ[̲a8+ ʹӎ֒Րҋ~H#Ty{iXu~|tȶq#iCnHdA nHnH?!  ( @ ַ87878787878787878787PNYddwdwdwdwzzzdwdwdwdwYd87SSzzz87SURQRQRQRQRQRQRQRQPNؽ||||||||||||^^^^^^]]\[ZZYXXXXĩyy|bbbbbbbbbbbbb`Xy~heeeeeeeeeeeee[z{hihhhhhhhihhihPĩ{{sklklkkkklkklkc|}oonooonnooooooU|xrrrrrrrrrrrrrmjĩ~vuuuuuuuuuuuuuauxxwwwwwwxwwwwv`{yyyyyyyyyyyyypĩtyyyyyyyyyyyyyyVxxxxphauĩ|Xxwu?!  ( @ hggOOOOOOMMMNMMNMMNNNONNNMMOOOONNOOOOOOMMMNMMNMMNNNONNNMMhhh}}LOJLOJ}ehdY[W@B>}LOJehdOOOOY[WrtqLOJehd@B>LOJ@B>ehdegdoo??@B>LOJehd@B>ehdegcOO@B>egd//^^NNmm]]{{}}ll>>NN||||llNN\\ll\\..NNNN]]>>==BB~~}|{{zywvtsqonljhfdqGGGGppFF} ggeeOO]] !!""qqooii""//112233}}jjxxNNjj 11??BBDDDDwwmm"" ::GGKKMMJJFFBB>>9944//**&&!! 447799::;;;;::775522..++((%%!! ?!  ( @  2::::::::::::::::::::+ '"b3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(qli+%"j3-(xpjxpjxpjRICRICxpjxpjxpjxpjxpj3-('"Y3-(woiwoiwoiwoiQICH?9H?9H?9QICwoiwoiwoiwoiwoi3-(3-(vnhvnhvnhvnhvnhQHBH?9H?9H?9QHBvnhvnhvnhvnhvnh3-(3-(umfumfumfumfumfQHBH?9H?9H?9QHBumfumfumfumfumf3-(3-(tletletletletleQHBH?9H?9H?9QHBtletletletletle3-(3-(sjdsjdsjdsjdsjdQHBH?9H?9H?9QHBsjdsjdsjdsjdsjd3-(3-(ricricricricricPGAPGAricricricricric3-(3-(qhbqhbqhbqhbqhbzPGAPGAPGAPGAPGAPGAPGAPGAPGAPGAPGAzqhbqhbqhbqhbqhb3-(3-(og`og`og`og`og`og`og`og`og`og`og`og`og`og`og`og`og`og`og`og`og`og`og`3-(3-(nf_nf_nf_nf_nf_nf_nf_nf_nf_nf_nf_nf_nf_nf_nf_nf_nf_nf_nf_nf_nf_nf_nf_3-(3-(me^me^me^me^me^me^me^me^me^me^me^me^me^me^me^me^me^me^me^me^me^me^me^3-(3-(ld]ld]ld]yuH?9H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9H?9yuld]ld]ld]3-(3-(kc\kc\kc\H?9H?9kc\kc\kc\3-(3-(jaZjaZjaZH?9H?9jaZjaZjaZ3-(3-(i`Yi`Yi`YH?9H?9i`Yi`Yi`Y3-(3-(h_Xh_Xh_XH?9H?9h_Xh_Xh_X3-(3-(g^Wg^Wg^WH?9H?9g^Wg^Wg^W3-(3-(f]Uf]Uf]UH?9H?9f]Uf]Uf]U3-(3-(d\Td\Td\TH?9H?9d\Td\Td\T3-(3-(c[Sc[Sc[SH?9H?9c[Sc[Sc[S3-(3-(bZRbZRbZRH?9H?9bZRbZRbZR3-(3-(aXQaXQaXQH?9H?9aXQaXQaXQ3-(3-(H?9H?93-(qli3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(3-(qli!  ( @ [lbp^lEV}zzyxyxGYGYGYGYGYGYGYGVmyqp}dr]hq~kxKYUeUerr~q~EWjzmytssdr]hq~kxIXTdUessrDWjzÍvttdr]iskxHWScTdtttEXjzĎwvtdr_kukxETPaSctttGYjzŏwwudr_kukxCSN_PatttI\jzŏxwwdr`lXdXdBRL]N_rssK\jzĐyywdrBRBRCS‡rr~rN]jzǑzyywdrdrdrdrdrdrdrdrdrdrdrdrdrdrzo}p}p~q~N_jzƒ{{yxwwvttsq~q~o}m|m{m{m{lzlzm{o|o|p}N`jzƒ{{yxwwvttsq~o}m|m|lzlzm{lzlzlzlzlzm|O`jzƓ~x^p^p^p^p^p^p^p^p^p^p^p^p^p^p^p^p^p^p^pkzl{Qbjzǔo{^pm{lzRbjzȕo{^po}kzScjzɕo{^pp~kyTfjzɖo{^ptkyVfjzɘ‚o{^pukyYhjzɘƒo{^pwlzYijzʘƒo{^pwm{]ljz˘ƒo{^pyo}_njz˛ƒo{^pzp}`njz˛ƒo{^pq`njz˛ƒo{^pnuYg`njz˛ƒo{^puZhdqjzʖƒo{^perjzjzjzjz^p^p^p^p!  ( @ 2:::::::::::::::::::::+&"]PHAKD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>|x($!XQIBj`WwlynPHAPHAPHAynynynKD>PHAg]TynynynPHAB<7B<7PHAPHAynynynKD>KD>wlynynynPHAB<7B<7PHAPHAynynynKD>KD>ynynynynPHAB<7B<7PHAPHAynynynKD>KD>ynynynynPHAB<7B<7PHAPHAynynynKD>KD>ynynynynPHAB<7B<7PHAPHAynynynKD>KD>ynynynynPHAPHAPHAynynynKD>KD>ynynynynynynynynynynynynynynynynynynynynynynynKD>KD>ynynynynynynynynynynynynynynynynynynynynynynynKD>KD>yn]WRKD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>]WRynKD>KD>ynKD>KD>ynKD>KD>ynKD>KD>ynKD>KD>ynKD>333xxxKD>ynKD>KD>ynKD>/7ynKD>KD>ynKD>xxx<<ynKD>KD>ynKD>q<<KD>znKD>000q<<KD>|pKD><<<p<<~rKD><<<o<<<KD>tKD><<<n<<<5KD>vKD><<<n<<<5KD>{oKD><<<m<<<333<<<5KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>kfa=<; <<rZ~N~jzvV6.jNjFzVV&fb>vRv ~R&^:f6fnBκrNrZ2jBR~zZ>~~^bb:^jVvVnZ6:VnFzZf>^6 vBrNvZ2jBR"~AQ7##B;*<A77##/T MEAL 7#/AAD 7##/AARK 7A ?A( 7A=%A>A9I.O2AW 65"I]4"=%NPX+5'] 26::::@53]]]P5:111]]]]]])115]]] 01 5VV]V[-SC]!,( @6\}, AVCLLLLP8LLubP LL{i^wTPLL}od{ZsOkEPLLLLzuj`xUpKhAa6P[4fopf}\uQmGe<[1}R%}N[4}vbyWqMg@{[<{[<{[<{[X0z[<ͻͻͻyri>ͻͻk[4i>Y+}OmAwW6ͻ~|[4sMsMsMS#sBc5]4 i>i>i>i>U$tA \:s[( @BNJZ³^1bfzvBrXfF&dO&&.rzfnFNd6~NvzVj~R&ZjBȮ:rR2*f:jjBZ6z^ R~z^>n~~vNZ*ʽʶZ.6>opz^f~zj{N"zJbξ&er^nRvR.\>ZkBn~z"^6*V'ʶl̺6^6zJz2rʲN~V2P. >JfnBrJMR~ZfvFzbRb:y2=R"bwV&Z>v~rZnvN&bjNl>.nzKvV]:~g*~Z:|3ªj~l: fV6bB"rJ"h:v~V*b:^2~frNV2 &r~6>ƶvZP*j>~_v_N\nJ&NfR"b6rZ2 vFRr~z~fz*.&r*zZnzR*®¶uJ`ʺβ>NnFTb>rRtBvzjnJ|NjFf>fBvRCCCCCCCCCCCCCCCCCCCCCCCCCCCCgRRRRllĮY%0?)LC2RoolQ>?)LvCI̝SRll(?)LCUѝZRlbj?)LC7ѝS bl0G?)Cuܫѝ̈́Rl4G?C/">ч R o44%/yaÄԄSRR440/@y"RRRRlll4jB^@ygRRRRllj .^'@"ggRRR0K.^'@g}T.AAwO'@Igf|AAAwO'@Ц|xtw홳O'@uuWʽq梾#w3O'yʽ+qq#~w3OK++qqxt#*w|+]]q #~c[w|ʁ+]]]q xt#:!E$Aeh]+_J #c!E{iJr 8J x#kN,Eixt#ckίP--Xi<酻 Ʌ#~ה5&9ip`Ji< ~c:!n`iJ:[FsXnPi;\ :[wٴ 6i1;HV xF\i<  9*[=i#~c:wd =;iiiiiiiiiiii$r1H??( @ +8EQ^jwj|'.?L>L  4= /lzn~%k|O\N\AMYk KZ?L)&_o1 l}j| &.&.  exP`q>o}j|[lg{L[3=awaw(Qbr Kp}k|4>3='/sL[r)Sdt[ X%q~ 7?j|(/i| g{fzL[dyo1<=K;I M. e67>5>j|4=3=Xjcx1;IY PedW6 qdW Mcdt[uI~pd6MX[q[t[x[zLߋ}p]MSRr]u]w]y[yY~Oߘ}o1MSAxgv^y_z]z\yYwUP|o%MM0xgxaza{a}^|\zXwTsNP|n1MM(v}pyc{c~c~a}^|[yWuQqLmGP{nOMM dwa|eeda~^{ZwUsOoJkEh@P{f[u_}ghfda~]zXvRrMnHjCf=b8PRt^{djigc`|[xUtPpKlFhAe;a6]1Pyfzcjlifc~^zXvSrNnIjDg>c9_4[/V)PpS{bt[t[w_ޘinliea}\yVuQqLmGiAec9[2wP(dBdF'iLz\>rS2}[8uPvPxn̲xV·ͻvfy]̲nȷxikDg?c:`4\/X*~R$rHa;P/ j̸~}y̲fƷ˻f=b7^2Z-V(R#zLnB]6O, [<±{̲_˾ȵtcvRi?Y+U&Q |LsDf;W0L(pVש̲zXȹͼŰ{j|YnF_3O yIrCi; ]2Q+M&Ƹ~̲tPôʸsatMe;T&tBj; `4V,O']9~̲oIkDg>c9_4X*T$P}LyGtBl; e4\/S'^9ǽ˿̲̲̲̲̲̲̲̲̲̲̲˱ȯªĶ??(0` BN±L[c8anWqBqN*L"&.JI^2vznvzX}N[ĮrMR2qgJdD jZ,l8zczrbO*hzm; "J"r^<&yJ ű`:mP.jBvX'^{^V&nHV2 vN#V*rjBrJZ4f}hV:~bB9̻V+gïzRiPz~dZ2̽ZM~ZrRmFCM, rb6 R$tEZj6>FrjJ5~j|6&r~Vj 2= ʶbzn~¾&R>Jj}w&N>~ƺ8W>"ȶjFvbr^:z^Bv^NZ^B&+f>Ͼ2ƶl>}~^zV2βrZxR.K&f6k,f>v^3`>5BJnJ&l.fvRbvFJwRʲW6r^.2vcªPnBZ6zR&X.jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjYYRRRRRRRR5+v8lH((i- `6yzr0jYRRRRRRRR5+vlH((i- `6yz0j=c)R1)RRR8lH(i- `6yzrj=<<RRRUQv8l((i- ``yzjRRRQ8lH((i- `6yj1RRR)H((i- `6jG1<<)RvH(i- `6jqGRRR)v((i- Hjqcc1RR)l((iZ_<R1RRUHZl{ҽd1%1<11RRRUl:dqYYRRRRRRRR5T:dYRRRRRRRR@ T::dqYYRRRRRRR^v@m. F> ::dYRRRRRRRR+_.FFg ::dYYRRRRRv@ԻFIg ::dYYRRR@ТIIII7g :dYY𤛻,III77g :dqYY^+{,,IIK77g :d,,kkK7g :ddY=9,kkk KEٱ7g :dd=q,kkWWW sKEUٱ7g :dd@,&&WW sKEUٱ7g dΝo,&&WW sKEEUٱ7gZ輨,&W sKE'Yj,&W KE'Jp#h##hh , sKKE''J~tI,&|CCC sKE'J~C&kkk&&|||C sE'b~N>X|CC||CC sK;VVbNTuS> ?XCC KVuuSCxp sKKEV$$B}Cex]?C ̏KE$[!!DDMuK"Ae?CW KEV[#WI\KsfA XCsKKE'uDpp" sя XꏏĎL *2ɳ3s"ƔAp?CEE''J~NSBMwnXCa3 X" ''J~>SMw֍2ɳƔxpXsK'JJ~>MwPn? a''J~>}/čeƔex "sEbJ~>}/P2naA]CK'~>}O/Pnp2ǫƔexX"f~>O2e2na?CsJ>4OhPnKEEKE'''>4OOn3p333e?(0`  '09CLU_hqz  )2;ENXajs}% ey 2< MZ:GQZdlu-$N\ M[L[q >J q AK@IS\fox5, Yj%-K[pbx1;.LU_hqz=4!4=h{Zk3<Xj1<Wi1;0;'Rajs|F='4=h{ 2<dycxbx{CcluNE-'.v[k@LL[2< KZKZEfnw[WN4 4=h{&-Yj2<Xj~  {XhpxgM_V:6>4=O\M[fz2<KZ1< $,&bgU^h_K&q}o}j|h{gzfzdy}*U  Fsixxxog^UL !E. KrZrGyyyxog^U/L8 5nWpXtYuIzzz߀wnf]Od:a7PzeMYu_xa~gjiigeb`}\{YxUuRsNpKmGjDh@e=c9`6^2Pe Ms_wa|ekkkigdb^|[yWwTtPqMoIlFiBg?e;b8`4]1Z-Pd;b7_4]0Y-V(S%}P!|M~OƬyZmid~cfhjoqpmjgc`}\{YxUuRsNpKlFiCf?dW9T5S3Q2Q0Q/ T0 kDe=pInT̲qųzkd`~]{YvRsOpKnHkDhAf=c:`6[1|T+oJ$a?W8dHhx\~`B{]=mKxW~[xSsMyo̲tɸų|n_}[zXwTrMoJmFjCg?eT5L/ítmf_|Xx^̲~uyWvStP«ýŴɵt~]}{̲qξɹıwlwTsNpKkDh@f=c9a6^2[/Y+V(R#xLmD`:S2J+ _A%̾Ͻí~~t̲l³̻ƴzpaqKlFg?e;b8`4]1Z-X*U&R#}OvHk@]7R/ J)G'ŵȴw̲hŷξɷ~sh~\mEd:a7_3\/Y,W(T%Q!OzJqCg<Z3 O+I'H&ʻ}̲cɻ²̻a6^2[.X+V'S$P }MzJtDk>`6 U/L)H&`@|̲^ƷϾɷįpe}ZtNj@]1W)U&R"~N{LxHsCk>c7 Y0O*K'J%о̲{Yʽóͻdzuj]wRnFc9Y+Q!}M{KwFqBl= c7 [1S,N(K%K$ʻ̲wTǹʸŰ{nc{VqKh>^1S${JvFrAk< d7 ^2W-R*M%I"ƪ̲sO̿Ĵμȴ¬ti\vPlCb6W(|LsAm= g8a3\/U*P&L#jRͿ̲pKmGjDh@eX0z[<ͻͻͻ`=7i>ͻͻc[4i>Y+}OmAwW6ͻ{fQ[4sMsMsMS#sBc5]4 ~:i>i>i>i>U$tA \:s[9( @ +8EQ^jwj|'.?L>L  4= /lzn~%k|O\N\AMYk KZ?L)&_o1 l}j| &.&.  exP`q>o}j|[lg{L[3=awaw(Qbr Kp}k|4>3='/sL[r)Sdt[ X%q~ 7?j|(/i| g{fzL[dyo1<=K;I M e67>5>j|4=3=Xjcx1;IY PedW6 qdW Mcdt[uI~pd6MX[q[t[x[zL}p]MSRr]u]w]y[yY~O}o1MSAxgv^y_z]z\yYwUP|o%MM0xgxaza{a}^|\zXwTsNP|n1MM(v}pyc{c~c~a}^|[yWuQqLmGP{nOMM dwa|eeda~^{ZwUsOoJkEh@P{f[u_}ghfda~]zXvRrMnHjCf=b8PRt^{djigc`|[xUtPpKlFhAe;a6]1Pyfzcjlifc~^zXvSrNnIjDg>c9_4[/V)PpS{bt[t[w_inliea}\yVuQqLmGiAec9[2wP(dBdF'iLz\>rS2}[8uPvPc?G̲xV·ͻvfwS̲nȷxikDg?c:`4\/X*~R$rHa;P/ j̸~kN&̲fƷ˻f=b7^2Z-V(R#zLnB]6O, [<±tk̲_˾ȵtcvRi?Y+U&Q |LsDf;W0L(pV̲zXȹͼŰ{j|YnF_3O yIrCi; ]2Q+M&Ƹȵٍzf̲tPôʸsatMe;T&tBj; `4V,O']9Ĵyj̲oIkDg>c9_4X*T$P}LyGtBl; e4\/S'^9ɾ7̲̲̲̲̲̲̲̲̲̲̲˱ȯªŷ˻??(0` %  '09CLU_hqz  )2;ENXajs}% ey 2< MZ:GQZdlu-$N\ M[L[q >J q AK@IS\fox5, Yj%-K[pbx1;.LU_hqz=4!4=h{Zk3<Xj1<Wi1;0;'Rajs|F='4=h{ 2<dycxbx{CcluNE-'.v[k@LL[2< KZKZEfnw[WN4 4=h{&-Yj2<Xj~  {XhpxgM_V:6>4=O\M[fz2<KZ1< $,&bgUEh_K&q}o}j|h{gzfzdy}*U  Fsiog^UL !E. KrZrGxog^U/L8 5nWpXtYuIwnf]Od:a7PzeMYu_xa~gjiigeb`}\{YxUuRsNpKmGjDh@e=c9`6^2Pe Ms_wa|ekkkigdb^|[yWwTtPqMoIlFiBg?e;b8`4]1Z-Pd;b7_4]0Y-V(S%}P!|M~OƬyZmid~cfhjoqpmjgc`}\{YxUuRsNpKlFiCf?dW9T5S3Q2Q0Q/ T0 kDe=pIe=̲qųzkd`~]{YvRsOpKnHkDhAf=c:`6[1|T+oJ$a?W8dHhx\~`B{]=mKxW~[xSsMeAE̲tɸų|n_}[zXwTrMoJmFjCg?eT5L/ítmf_|XtO̲~uyWvStPýŴɵt~[w\A̲qξɹıwlwTsNpKkDh@f=c9a6^2[/Y+V(R#xLmD`:S2J+ _A%̾Ͻí~{[V̲l³̻ƴzpaqKlFg?e;b8`4]1Z-X*U&R#}OvHk@]7R/ J)G'ŵȴr̲hŷξɷ~sh~\mEd:a7_3\/Y,W(T%Q!OzJqCg<Z3 O+I'H&ʻԊrY̲cɻ²̻a6^2[.X+V'S$P }MzJtDk>`6 U/L)H&`@Įo5̲^ƷϾɷįpe}ZtNj@]1W)U&R"~N{LxHsCk>c7 Y0O*K'J%оd̲{Yʽóͻdzuj]wRnFc9Y+Q!}M{KwFqBl= c7 [1S,N(K%K$ʻ̲wTǹʸŰ{nc{VqKh>^1S${JvFrAk< d7 ^2W-R*M%I"̲sO̿Ĵμȴ¬ti\vPlCb6W(|LsAm= g8a3\/U*P&L#jRͿǵ̲pKmGjDh@e>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~fyeefeeeeefeeeބee℗eマe愤eefƴ`ʄf쿠sbi߄ejÃegm( @|||߼||||||||||||||||||||||||||||||||||||䙙|||晙|||虙|||陙|||뙙|||ÿ||||||Ѽvvvљ|||̲yyy晙|||̙ۙÞ|||~~~ᙙ( @  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~OPOOUciiiiiiiiiiiiiiiiiiֿҜݰ߰OOPOPOOPPPPPPPOPPPPOPOOPфOӄOԃȓOքЖP׃؛PلߜPڄ柢PڄO܄PބO߄POᄣPყO߄PNۄKڄɾT؄ni[[^mtX݄fsO߄ķdnǿ}cnȄt^zzhZ~qcZwj^{s?( @ fffffffffgggiiilllnnnoooooooooooooooooooooooooooooooooooooooooooooooooooϳ̂ٞⰰffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffڙƢfffۙͥfffܙԧfffޙڪfffߙ᭭fff篯fffᙙ첲fff♙򵵵fff㙙fff䙙fff噙ffffff虙fff癙fff晙¿fffddd㙙aaaᙙjji¿rrrrrruuuoon䙙}}}eee噙{{{癙yyyљtttü~~~qqqžzzzqqqttt귷ܨ?(0` 9W/ o< GKNOPPPQQRTUWZ\^!`$`&a(a(b(b(c(d(e(e(f(g(h(i)j*j+k*l-l.m/m/n0o1p3q4r6s7u7w9y;z<{=|>}?~@DGKMOPPMKIHIÉJŊKƋLȌNɍNɎLːK͒NϔTЕVіWҗXӘYՙZכ\ٝ^۞`ܠbݡcޣdߥefghijjkmoqsuwxxyzzz{|}~ÉƌÊ켇޳̧xtnvkrmfdcbbbaaaaaaabbbeffhjknppuuuwwwxxxxxxxxxxxxxxxxxxxxxxxxyyyzzz~~~Ƥکѡߢˏ̡̡СƢѡϣԡڣԡݣڡ㣣ڡ餤ۡ𤤤ܡ񤤥ܡݡߡᡣ㡤䡤䡤硥硦塦䡨㡨ᡫࡳܡõԧǼۡڡڡúݡݡߡûǼ۠??(0`ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffŤnnnͮ}}}׼ԔܣffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffљàfffљȢfffәͤfffԙҥfffՙקfff֙۩fffי߫fffי䭭fffٙ篯fffڙ찰fffڙﲲfffۙ򴴴fffܙfffޙfffߙffffffffffff♙fff♙fffᙙffffffߙeeeޙdddݙbbbbbbڙֹmlkٙyyyuuusssrrrsssvvvjjiؙ{{{cccיwwwkkkۙwwwjjjۙvvviii퉉ܙ˿sssiiiޙqqqiiiǙxxxmmmŃ~~~sssnnn؏þzzzssspppߛwwwpppsss宮ý}}}ttt䰰Ǖ ?(  @||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||vvv|||yyy||||||~~~ ( @ fffffffffgggiiilllnnnooooooooooooooooooooooooooooooooooooooooooooooooooofffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdddaaajjirrrrrruuuoon}}}eee{{{̪yyyttt'~~~qqqgzzzqqqÝtttѬx(0` %ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffnnn}}}ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeeedddbbbbbbmlkyyyuuusssrrrsssvvvjji{{{cccwwwkkkpwwwjjjvvviiiCsssiiiqqqiiixxxmmm&~~~sssnnnWzzzssspppvwwwpppsssǥ}}}tttіH ?! hh f  0000^- hJ  nN00 %_( @tttwwwzzz|||  ,68CAL\}V#()\b`" &)`[*%'']''c$''VJi]''VUJJmi]''WUUJBA''''VUUJJBAA8JUoUUJBBA:8:UUoJJBAA8UoooAA82kkk+oooooolgkh:8ooo:8+kg+8:o:82g2888o82+8:2( @6\}, AVCLLLL|||8LLಾ||| LLļ|||LLſ|||LLLL½|||zzztttttttttttt僃|||ՠ|||€|||wwwnnnÊ( @  &.1;1<2=4=4> 7?7>ALBMJZN\VhYkZkdyg{j|k| l}o}p}%q~WWWYYY]]]Pgm```bbbeeeiiillkmmmponrrrvusuuuxxwyyy||{~~~rt{}6!,ucYZQdQ@ .0(     (+;8%%;=116>XEIMLMNMMMMQSSPS[^]_ced`bjnqrtw~KMWX]dfnpq{|}~JJJJJJJJJJJJJJJJJJJJJJJJJJJJOxxxxooooooggggqtJR}_oNKo7gcq@JR= 0o=2Kggc?JRx8 o2 ggg9rJTx= o 0/ggg9_`JRx5 oK K\kg9g_`JU 5xo o 992_``XU6 5xKx2o/22g__cU{xxxxoookokogkggggGUxxxooooookokgggD"UڴxxxxxooookkkkF"^۷xxxoxoooooIA#^۷xxxooooYA#^۷xxxxZB"^۷}[G"^ڷdD"^eH"||x|xx|x"ĺ"ĺ"ĺ++&&&+ ĺ&##"""#'&+##+&#(+**+#ĺ+#"ĺ&"ĺ++#+ĺ+#"#+ĺ+&# #к??( @ +8EQ^jwj|N] ,L]n~%k|O\ALudy!=N_o1 l}j|4>g{'/Zk'/2=;P`q>o}j|4>AMt&.Yks(Qbr Kp}k|BM 3= )Sdt[ X%q~ 7?j| 4=3=dyJZ{;I M. e67>5>N\Ykr}1<1<1;Vh PePgm qdW Mcc]]]~pd6MXYaaaߋ}p]MSQdddߘ}o1MS@fff|o%MM0fff|n1MM(ufff{nOMM dfff{fZfffQffffffޗddd񠠠bbb|||zzzvvvssstttxxx```uuukkkfffcccbbbdddjjjrrqponmmmhhh||{ssrllksrq{{yvusxxwļ~~~kkkZZZ煅zzzhhhYYYcccžsssbbbWWWúwwwiii]]]YYYxxxnnnccc[[[ggg{{{sssjjj```hhhɈ˯??(0`   &-2<4=@LN\WiYk\lbxeydxh{i|k|fyTTTYYY]]]aaaeeehgdlllqqquuuxxvyyy}}z}}}st%,28?{{|}essaaP|P@@8/ z *-24!)->2:natA_XSXXAIMMMMMMQVQVY\Sccdafimqvy}CEKLRWWT\bdhklfmu}~GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGKhhhhhhhheccccecccccVc\guw{GKlihhhiiiehehcccccccVVb\guw{GKsp- Vee%ecHccV,uw{GKxr- eh ce'cVV,guwGKzs2ih TeeHcVc*VV\uGK|z2hh)-Je%ccc*VcVV^wGO}|3hh/&.I  ccc*VVVVVV]GO|4hh/)V% $Pcc,VVVVVVV]GK5ih)- e -*cc*VcVVVVVVw[QQO6oiVe ,Pcc*cVVVVVVV^]VQOF hh$Vc % VVVVVVV]V=O8 U/&h-hccVcVVVVCOmoihhhhhhehccchccccccVVVVVVʹOzioihhhhhhhchcccccccccVcVSOohohhhhhhechchcccccccc~9Oвshhhohhhhhehcchceccc>Oвohohhhhhhhcchcccc@Oвsihhhhhhhhehcce@OвohohohhhhhchDOвhhhhhhhhhE:Oвpihhhh69OвzihM>OвϫN@Oвҫ^@O䲥eDOiF:oooooooooooo9!!!!!!!!! ȿ!ɴ!ɴ!!!Ĵ!Ǵľ!!!Ⱦ??(0`)3>JU`kv *4?KValw N]fz2=fy*5@LWbmx!4='-N]3=Zk dx+6AMXcny*!i{@L 3=eybx-BNYdoz2*i| &.2=cx2OZep{;2j|h|YkYk cxP[fq|C:%j|h{3=@LscxQ\gr}ALC,j|AM'.M\fzcx4R]hVUL2k|5>4>N\ezcyHNMM]T85>\lh{t @L2=&.2<WiMMMaef]? O\3=&.ez2<MMM_|wwwnf]TK MMMX醸ĊZZZxxxwnf]S)MMMSz̈́]]]zzzvne\NMMMMt{```߈vme\MMMMnscccߑvmeEMMMMcaeeeߙ~umdMMMMXafff~ulWMMMMXPfff~ulQMMMMS@|fff}tlWMMMMM8|fff}tlc-MMMMM/sfff}tkcbMMM afff|hMafffRPfffd@}fff{fffzzzԎfff㘘ddd񡡡bbb~~~{{{zzzzzz}}}aaa|||yyyxxxvvvtttqqqoooooosssyyya``xxxqqqkkkiiigggfffdddcccdddgggnnnrrphgdrrrggg```\\\[[[ZZZZZZ[[[^^^iiissqoolool|||nnnbbbcccxxvqqpwvu}}z~~{yxvsspxxxǯʹ}}}pppaaaWWWPPP|||oooaaaVVVQQQwwwjjj^^^UUURRR~~|||qqqdddZZZTTTUUUĿ|||sssiii^^^WWWUUUmmmؑ½|||uuukkkbbb[[[XXXVVV᜛|||uuunnnggg```ZZZXXXmmm䧧~~~xxxqqqkkkeee^^^YYYmmmܰ}}}vvv~~~˭з??(  @6\}, AVCLLLL|||8LL||| LL|||LL|||LLLL|||zzztttttttttttt7||||||񂂂|||wwwnnn:9( @ +8EQ^jwj|N] ,L]n~%k|O\ALudy!=N_o1 l}j|4>g{'/Zk'/2=;P`q>o}j|4>AMt&.Yks(Qbr Kp}k|BM 3= )Sdt[ X%q~ 7?j| 4=3=dyJZ{;I M e67>5>N\Ykr}1<1<1;Vh PePgm  qdW Mcc]]]~pd6MXYaaa}p]MSQddd}o1MS@fff|o%MM0fff|n1MM(ufff{nOMM dfff{fZfffQffffffdddbbb|||zzzvvvssstttxxx```uuukkkfffcccbbbdddjjjrrqkjhmmmhhh||{ssrllksrq{{yvusbb_G~~~kkkZZZ4zzzhhhYYYcccysssbbbWWWwwwiii]]]YYYzzxxxxnnnccc[[[gggyyx{{{sssjjj```hhh7·??(0` %)3>JU`kv *4?KValw N]fz2=fy*5@LWbmx!4='-N]3=Zk dx+6AMXcny*!i{@L 3=eybx-BNYdoz2*i| &.2=cx2OZep{;2j|h|YkYk cxP[fq|C:%j|h{3=@LscxQ\gr}ALC,j|AM'.M\fzcx4R]hVUL2k|5>4>N\ezcyHNMM]T85>\lh{t @L2=&.2<WiMMM[6f]? O\3=&.ez2<MMM_|nf]TK MMMXZZZwnf]S)MMMSz]]] vne\NMMMMt{```vme\MMMMnscccvmeEMMMMcaeee~umdMMMMXafff~ulWMMMMXPfff~ulQMMMMS@|fff}tlWMMMMM8|fff}tlc-MMMMM/sfff}tkcbMMM afff|hMafffRPfffd@}fff{fff fffdddbbb~~~{{{zzzzzz}}}aaa|||yyyxxxvvvtttqqqoooooosssyyya``xxxqqqkkkiiigggfffdddcccdddgggnnnrrphgdrrrggg```\\\[[[ZZZZZZ[[[^^^iiissqooljif|||nnnbbbcccxxvqqpwvu}}z~~{yxvsspddaF3}}}pppaaaWWWPPP|||oooaaaVVVQQQwwwjjj^^^UUURRRnmk|||qqqdddZZZTTTUUUE|||sssiii^^^WWWUUUmmm|||uuukkkbbb[[[XXXVVV|||uuunnnggg```ZZZXXXmmm~~~~~xxxqqqkkkeee^^^YYYmmm~}}}vvv~~~V?!  ( @   tt~ww|++g44cczxxx^_\]fggkgkkǭ[lbp^lEV}zzyxGYGYFXAQKD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>($!XQIBj`WwlynPHAPHAPHAynynynKD>PHAg]TynynynPHAB<7B<7PHAPHAynynynKD>KD>wlynynynPHAB<7B<7PHAPHAynynynKD>KD>ynynynynPHAB<7B<7PHAPHAynynynKD>KD>ynynynynPHAB<7B<7PHAPHAynynynKD>KD>ynynynynPHAB<7B<7PHAPHAynynynKD>KD>ynynynynPHAPHAPHAynynynKD>KD>ynynynynynynynynynynynynynynynynynynynynynynynKD>KD>ynynynynynynynynynynynynynynynynynynynynynynynKD>KD>ynKD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>ynKD>KD>ynKD>KD>ynKD>KD>ynKD>KD>ynKD>KD>ynKD>mgbmgb$KD>ynKD>oTiSDQ>8Q>8hRCmRW1O=8KD>ynKD>oVTB;pZIaqpaqYHTB;mR5KD>ynKD>iUF`MAuغٻغط׶ִn_K@hRC0KD>znKD>rXr\Lˮڽڽڼغ״pjTEmRKD>|pKD>R?9|ÏŒƔƔƔŒÏڽٻD]6_R?9 IKD>~rKD>mVzfSĒȖ̙̙͜͜͜Ȗđt@^5La:u]JgOKD>tKD>iVH{ɗ͜ПӢԣӢvQpAFg:Bb7Pg>dhSEKD>vKD>O=8ֿ͜Ҡ֥ڨ۫ڨ֥ŒTuDIl=Ee:Y˪zO=8KD>{oKD>O=8ÔП֥ݫxݫ֥gKo>Gj;[ɫ|O=8]TLKD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>KD>jWIӢڨXKڨwYIl=ziiTFr\{iVԣiVODWLo٨ԣƔejQڿq]LjS8+(-Q?:–yr^NFj\‹ŒYJ~R?98+(-|cweTΟ|eaSyjYJb̙иn[KrXO=8kZJq`P×ڨƓgfy͜ɴdQEiVHO=8O=8|c[I@~o[̾ʺz{iVVE=u\O=8O=8O=8O=8D50%|ckZJP>9P>9iXJw_D50%O=8O=8O=8!  ( @   yfr`p]mZmYmYmYmYmYmYmYmYmYmYmYmYmYmYmYmYmYVJVJVJVJVJVJVJVJVJmYVFVFVFVFVFVFVFVFVFmYZNZNZNZNZNZNZNımYh]h]h]h]h]h]h]h]Ʋ˱ȫæyrmgmYpipipipipipipipidzmYxqxqxqxqxqxqxqxqȴ˱ȫæyrmgmY}}}}}}}̶mZ̶6V0P)Jp]̶<]7W0Pr`ynv|̶@`<\6Vyf̶@`@`<]u̶̶̶̶̶̶̶̶˶˵ʵɴȴdzűı¯}oXn=uJ2=+N6VFh1e/e/a-`n\uE"d-u^LH:s6fuzCo4o9N6ÇBǞEWbۖPNڋFˏA‡>i[,X0x8jN_EԜEԜEؖFۚGWAfڐFϓCcX+l2‡>_juYکHҦIүVүc`ϰ_AVG}we/s6ϓCyX|in޲Kֳiڷڼᶀ}LaKh1:ԜEuYqk]ڼśάαȣ㺄=[םؖFq3<ۚG`qilҵPuH[SÂ>ǞErSqZnÖսnDǸΑ~ԿbP[Pc[PǠڷ|y=a=[ªƭҵնάֳuҹǞE}I_f㺄ڼָxӦڷb|cbֳ^ֳlָuŐ???????????!9GIF89a }{~EKT궸ǕRV\quzޯąFy{~ɮ4=IKQ\ꁄSX^afn9@KSot{gimtx|2j苍lqvISaݞ器6;Bbej'-7ejqqv|uz [KOT蠢-fMXfَJmryNSWgkoWanQ[c/5<&S\eٚW\`Ƹǯ򌒛adgQ㞠ټOYh$SehmޙDzP[jinuЙ]bgV[b9?J\fs✞#+#(1׿08DRWdglsuw،岺ïxӰ搓%]@DJv!,  H;BÇ))H ȱ?C`GY1+';fC'K6Xa6ohѣFp g̘K 2dɊScQ> $ Ы;&\؇LUfRX>`Cqȑw-\`(@ 9`sr+3qE8tt$HƑ, +?%R CIa$0B 20B{9 r2\ryHR6d$xĩ!$ǝw&)qq4PĢH6#|DG!L (E23LLƧ*siA2I%pN*R  PC9tE n+n!0P^ 2&TkF[A$a:4Ԃ%\3P(XO?g +ǿ&lZ?42AÀ'=TlqEP1?3S$=ȡrE0?, p$sp"d@@:tD-5h hA /'l@n<@ h&$@nݱ3% I |7"q6nkPԇT;!n PNG  IHDRdc2gAMA a %IDATx^흉vHE{Ӊ(V%HLBYO vӶםu't׭ *:/'SynYPz+n k&{CL,, dd=={&[r/ɭ#PY}3+UNG`>q,ܪ'|bzX q8d= Ed=*lҢ@>uOL`}"&+Izy՞N?5uQFKo~Hxs#;&XZZʞ>l]x2+4/ eK}Q޴#9A%0q-7_y,.4Oˣ0? V!+YIQ,v L$ׇ*j,/˜+1/Dqyk,X o^o%חldW8+^7vU fy6̯/oW}ቋ}?96^yfxѹfaf `ÄU4̚N/e2;{inGI{7כe)kŬJa8[aYj477]7M0k[*Z/LW[q3M긞Rfe3X}efهz? aV* öqM!71u2`V)s ^;,*wnE(H/dm0;?\zOeg?1Ie]o˫lF̲(.U8Ku Ab5RU"@m9~#L)ڎ/eWJT\_cA0j$M,@ 8#369OrIbv`sA,s n'7\8IEI|qUl&/UhZ# 8_#.HOL=GJ:047;h8EQVk"Y Chòr. Ep$,n5I2Gt;)TNiϢH66;"ćxi*\*jџlfeV}Xdz?@U$^?C 'bԕ6aיUq@ՑO+`eO4BNՎ[\쯣*/Jhy:{9X/AKĈ(/-#§n45HO Kn bfil?yDS0Qđ?JAL݈GVv}k&<vqVp,c5ɇ4Sn23уhyƒ5QdEH"@{CADȇӶA1oueY`%9 /1@踐AmU:%㕶=I29S$HBBUzTjɘ/GK'ZmWonb˥0w'W>Lrr]BdW=#P,} ZYE @愬ɘB.6p/AA-Vi`R98-x9^ȣ /CyIN~sHd1NS9uX琦G],A.Z@@a|#Q^*KzXe5Uh @XdrCU)JBwe9/GVx 4dFޚ*N-? y ˆ0rD(uURRecLz txITs0@[@y9JN֨HP6|,rќAHu#Zo&35J$SW䊆ZqPB^K],Ў˜QFK9NX@NIk!6Hy-D']] :5< ^=s-㒎@&|=EQB)u<+J>I~Lbmcxo2MejucKW&Iۭ *?EHJYP$lLp3z2^$RCJ&XPy8uWIqsѝ#.NQefKs7QK/0.gq!o^{D#n+L`}㮃n&;GPʋs7R#DTxynN` 9'gkkasBIT|d pHYs  ~tEXtSoftwareAdobe Fireworks CS3FtEXtXML:com.adobe.xmp Adobe Fireworks CS3 2007-12-18T17:25:44Z 2007-12-20T19:26:11Z image/png $tEXtCreation Time12/18/07#Xb+IDATx]kegv^`eۯ!x#A~ZHKE+ CKWBJGB&;I#l$۩ g-&<3#I%b pppppppppppppppppppppppppNS‹/d<_-ۯkRU Ϸ~ͩ"U$q`x8`em:4ZxB6AF )I8=Z0GDa$ E?{K#cK !6Q,Xpi1tI4 bCgPaL{p [()"/I/5~r :jC/@A"D!v7[pY٢ ޾-]Yu[Ѕ2'IV_\Wqܜ=F$ӏwp;xs慬fz5|xu3ӧ g;wڹk˗ў5/h"t`D?͵qe-kS5"n/ƭxK8 ɡ!z'ct6pDANj@QF^ש;G3 SwL!rN1t Qeԝ@/0IJ#G :Sw"1ԝjG@1P[lg0 ofo&T`mIWc0v0(x h%]нƸAt/ AO4<C@ZQN+4#`hv`)w1 ykNu cy?`YPaL8at @Oi%gQ 00!AÒrp8h<jC-@ǀM<{PJNFzAmH$^}teRϞ9}{ CCCCCCCCCCCCCCCCCCCCCC7!0`IENDB`!~ h(  slgH?9H?9H?9H?9H?9H?9ngb{w{w{w{wzvH?9H?9{wH?9H?9{wH?9H?9{wH?9H?9{we^YH?9H?9H?9H?9H?9H?9zsn{w{wzv{w{w{{{w{w{wzv{w{w{w{wzv{w{w{w{w{wzv?!~ h(  pidH?9H?9H?9H?9H?9H?9H?9pidzuzuzuzuzuyuH?9H?9zuH?9H?9zuH?9H?9zuH?9H?9zuH?9H?9zuH?9H?9zupidH?9H?9H?9H?9H?9H?9H?9zsnzuzuyuzuzu~z~zzuzuzuzuyu~zuzu~~~~zuzu~~~~~yuzuzuzuzuzuzuyu!~ h(  """?RKF""0"0""RKF""""RKFRKFRKFVOJ}UNISLGRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFRKFĽRKFRKFRKFRKF?ohc=RKFRKFRKFRKFRKF0##s/cckus/Dkt/QuptecQVCO!~ h(  *&%*&%*&%*&%*&%*&%*&%?.*(_SOM򝙗QMK.*(.*(?2.+UQN~{UQN2.+61/~zwLGDJEBlhe:5261/:52VQNHC@?:7>95|zFA>B<9IDAIDAF@ H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_F7IDATxbFFFF(90d6V0S0CDrϵ4!+vIENDB`! PNG  IHDRRW pHYsod OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_F6IDATxڌA Òy^TT TjUgLKIK]%]|0v[ yFIENDB`!~ h(  www<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<K}xhB\0 qJ[na8K!8s̻~/zwfys A3~4#gLJ2WƋY~mN׋OFpүY\C!ёHR hw{vm,,(LoECxk,.oۗm81>RtF\!n::.Q_=73j5M-,4kKOWM'02Xpݞ_jCsylh GkxQفf/B*K\\o62,>isIn6c`L2@|LSMUl՛XLǯ}1M?w09OG!b.=^n.kK l<)Ɍp|(bAMlj\XuglƱa  qKϰ 3j`rtC<T(oWI Һ'+d\fkOR;5q~VpZج|}yr#K-D*ıP4QD#*}4mo6HXlR-NAFiG:UWxG*@e}{pVSDtH',bY9B1B]5m[$( $-~۱{f͠(rjMjC@!ѣ#Zow(>!#cZXHY}1>#rI˴ h4Yk/QPh]5}Z{GRqQBiyfB>ї 8O37^Tgj@ө$7z&i4 *IIxԊ Adobe Fireworks CS3 2007-12-10T21:30:37Z 2007-12-10T22:29:20Z image/png tEXtSoftwareAdobe Fireworks CS3FtEXtCreation Time12/10/07JCIDAT8JAi hܞKa)X,'lV0+ZmLƣ}>z`>UA-}>5W"K.Z IXG뢭;. |}>,M"rJŹvF+7-!X`o .5nu&DM\r=.E=~&xCɵMf b]tҟԘeV>4,zec:'ίIENDB`!~ h(  333qqq333fff3333-(RMI---------333fff3333-(3-(}3-(------3333-(3-(------3-(3-(------3-(3-(------3-(3-(------3-(NIE---------ricricricric3-( .ric3-( . . .ric3-( . . ric3-( . . . .|3-(3-(~3-( . . . . . .###8!!~ h(  aYUaYUaYU`XTaYUaYUaYU`XT`XT`XT`XT`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XT`XT_WS`XT_WSyt_WS`XT`XT`XTytyt_WS`XT`XT`XTytAA2!~ h(  :IEC3/-ifeڏ:3/-fcbhecڐ3/-XUTqom3/-IFEzwv3/-HDCxvu3/-ronb_^3/-miha^]3/-FCArpo3/-HDCpnm3/-þSNLgdc~|{3/-b^[[XW|zyC?=842ZWVwts<xutvts;1-+1-+1-+??!tPNG  IHDR szzgAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxWnUk}6'!'\icG"E"A%" xijZDX6`||k(/-o=Xc1(Org~pܹA}Rw>ލtReh\v<ӽvsIKC߻8%:^P0:I䩠:6c0(o&;K̵O߽Xy,7~k3o(@ŝryR9t`w..GB$ޓ'y9y#hn o -Ɂv?Fzy؇3_^F.M@8SHX]UL5αa}n]{D )AL) D_3y| 4Хi<L(,{e=q]7ZR˘aAQ[Iz@"L3>E & GPRjj=?=#-y%I%BFdfL( Hbd% ͼv.〈=bi߳rúfd8}C!ܣHĹ<V*mדVXTrB̕R ABrklVTkXI  }}=Y&aݍv:m#o wn-ӂ%,zV TQiLXx\֝`Lt~MbI;~5 FAF/E|'¥RfbP|6IhɄd;tCez}UatlԈ S^!KWJtQ |>QphA2_\ǃ&{w6CEI:a~q0 R(\;K-0G (,]iܾcNhs %$=X/ ~V>S7:GtdR)F'j/`r>+vN"*Wy &* H!:ƬM2C}2"FZ-2ɫν?"\gIR9z{sY Bժ"xƧΘt!y Uy3ٗz'AZʌiA67Vdv/l#H/ֿ9Uo㛦$ Iі]΀V˾>.P ڐX7׎l=o4g˥\F)V})k{A=2}g=|'j&|\*IENDB`!~ h(  aYUaYUaYUaYUaYUaYUaYUaYUaYUaYUaYU`XT`XT`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XTaYU`XT`XT_WSyt_WS`XT`XT`XT`XT`XT`XT`XT`XT`XT`XT`XTyt$$$$!PNG  IHDRasBIT|d pHYsodtEXtXML:com.adobe.xmp Adobe Fireworks CS3 2007-12-10T21:30:37Z 2007-12-10T22:29:22Z image/png oYtEXtSoftwareAdobe Fireworks CS3FtEXtCreation Time12/10/07JIDAT8NB1$:3 ԡ28r4!L>o8kh}YpK{SK۩z*Y'h=M]HF*]`` <:k~CN4 &JGaGo<0v̛BT3h?v4 3nwe)@sBh0rl+px5%Ws` H'pp{$ryAɵPWn$IENDB`!fhFh   ( rc^fffxhb~lfuqfvsiyvn{xr}zu~zqkvo|zsw~|ΩԮžĠƤʪ̭ϲҶӹռ@,>>:,642,...,.? . ,@ 6# .@%+(! .A&/+#! . ,@:72($"2A-?:7/(#2AA?>:2+(6,A'AA@@?72/7( fffffffffffffffffffffffffffffffffffffffffffffffffffԮ}zu{xrzworc^vsiuqf|ԮĠžžԮfffԮԮrc^~lfvoqkrc^xhbΩԮԮԮԮԮfffԮ~zږwyvnռԮ̭ǥžԮfffԮ|rc^ԮϳʫƤԮfffԮ~rc^ԮӹϱʪԮfffԮԮrc^vozsԮԮԮԮԮԮԮԮfffԮԮԮֽҶԮfffԮԮԮռԮfffԮԮԮԮfffԮԮ~lgΩԮԮԮԮԮԮԮԮԮԮfffԮԮԮԮfff( @yhxq{tuwzz}ЫԮž ĠĢƥȧȨɩˬ̮ķ»¼ľγαгдҷӸԺռ׾ؿ\iifRdd__R]]]]RTTTTRTTTTRTTTT:_ ---)----)---T:_  11--)----)---T:d  421-)----)---T)))))))))))))))RGi]]UJ =)7722)----)---THh`]] 0C)=672)----)---THh``8MC)@=63)2---)---TInd]MMM)C@66)2---)---T)))))))))))))))))))RHn L]]QQ)FC@@)722-)---TIn  (]UUU)MFCC)7722)---THn K)`^]U)MMMC)=672)---TIn 'f)``]U)UMMD)@=63)2--T)())))))))))))))))))))RIn  Snh)fd``)]QQM)D@@=)72-THn ,nnl)idd`)]UUM)MC@@)722TIn lnnn)hid`)]U]U)MMD@)733]In nnnn)hhid)`ZUU)MMDD)=63U)))))))))))))))))))))))))RIn"l)nnnn)nnhh)d``Z)UQMM)C@=]Hn\n)nnnn)nnnh)fd``)]QQM)D@@]Innn)nnnn)nnnl)idd`)]UUQ)MC@_&IIIHIHIIIIHGG::++++%%#_( @ yhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhϋyh»ڛxqxq|zwuxqžžžԮžžžžԮžžžϋyhýݜxqxq~|zw{t¢ĠžžԮžžžžԮžžžϋyhĿរxqxq~{yȨƤàžԮžžžžԮžžžϋyhԮxqxqxqzxqxqxqԮԮԮԮԮԮԮԮԮԮԮԮԮԮыyh蠜xqÒ{tγԮͯʪǦŢԮžžžžԮžžžϋyh롞xqҭxqԺԮϲ̮ʪǦԮžžžžԮžžžϋyhxqķxqֽԮѵϱ̭ɩԮġžžžԮžžžϋyh򣠜xqآxqԮӹѴαˬԮƤàžžԮžžžϋyhԮxqxqxqԮxqxqxqԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮыyhxqϠԮؿջҷгԮʫȧţŸԮžžžϋyhxqЫԮ׿ջҷԮͯʪǦŢԮžžžϋyhxqԮԮ׾ԺԮϲ̮ʪǦԮžžžϋyhxqԮԮֽԮѵα̭ɩԮġžžϋyhԮxqxqxqxq{tЫԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮыyhxqԮԮԮռӸдͰԮȨƤßϋyhxqԮԮԮ׿ջҷгԮʫȧţϋyh{tԮԮԮ׾ջҷԮͮʪǦыyhԮԮԮ׾ԺԮϲ̮ɩҋyhԮxqԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮыyhԮԮԮԮԮӸѴΰ֋yhԮԮԮԮԮռӸд؋yhԮԮԮԮԮ׿ջҷًyhǶǶƶľ¼¾ۋyh!PNG  IHDR($;H pHYs+ OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-gAMA|Q cHRMz%u0`:o_FIDATxb?:`1?<{QEX3qa`````a```nƗק3~?3T 0N]#z(|ҋN!J)籟kI_-ed= 03'kxos. "o}JH#q薈0Xo 9kRDJ +@ ڗ313[`{ L`bDgbbb0psa͛:bg<#&r>&ΰh1o_Ǫ߿݇K߿V}>G~IK ӧ#|wbx꿨(#ϟ? W ?톚, 5382ұJP\$EDA28Э/OhA[*4nM IҘb:4!J*xƟ_v( ض 4hvyrmxr˲ 3Ds*ri*Q [Xj%6jjV/ktY],eIf9g&i_d6V춡if'] fS(Jԗ딐C&c 4ԟCz<i/A0(V!4L5pOs""ȸc CEѥ臭P:{w9U|KuQ8s-AJ!mD΂1 ޮaͪ,Ie-e])o.z Z@+~*U i-hb \rY2TUmMm7`>?.069p[e%(r {@=<3S@f]%Prcs|R" qF|c6MaM6YmQkAPA<AP/?W^6s ###/_YMkfc%LFjg-,R?K!R0AIENDB`! PNG  IHDR  pHYs+tIME )atEXtAuthorH tEXtDescription !# tEXtCopyright:tEXtCreation time5 tEXtSoftware]p: tEXtDisclaimertEXtWarningtEXtSourcetEXtComment̖tEXtTitle'IDATxmpU"C: hJh% e0-q2t~Vk[k e4 "P_`};gݧNbٙsfΞϳ3pf~Q=gl6(= 7} #k D^+f(,D^Ll$IFGG.Ƽ@w<PVX AA:dǑH`l,yI DR<IDAT/w«1c}4X8"A:tHp ƎJOǾJ bӧtb>Zd2p]xq&|dCO?3zΗ ~\_**PV"ò2RH$@)p@ B@6fNqx)Ǐ7< rH$H pyy@ $%ZDI˚;Oxp|ŊiѨEEl~j{6MŘK$DAp34IDAT])sR "0\  GǘHnj(="Oki-G)?QJ(*(H)@HږZ ""`5ʧRkI֎֮֮Y$i7Zh-D.ttC!1P}2~rM\40cq\ZkTcIDATwtu|񔯉DsmRH !Resg!J]^w]GOZ~6|}'6oNd# A]MI$#:aCSO.uo`#+Wض hj~[. aL *+-+psp6mNSÎw1ٽizyy#X?l ***fr֏6p[IDAT3I?vz. Ѐ$_}`ժ?.d;w,`8Hkk80Y`,ر+~$1Sɽ{O] RSs}#%sM7ބ'zkZOۭHoDbL)=oؐ`(B@/Qlɒ%;y~j1"" 1 `Mz|?. =yrx@c^ Z[6S[[Om/֞Ϙf̞sIDATD8@}gr3vè+}txj;-36`IzvR,3w > z0jtik[6K)㏥t@yW}Oi?|8`c#:wvv~p~{ÿ~6vEH) QƎQT^qѷۿѲ4r[o޿B.BD c~ˑhqiIsKKˬYȹo>:'9{&L !"ƷPIDATy0,,,uέ_]]mB ?fIENDB`!PNG  IHDR>asBIT|d pHYs  ~tEXtCreation Time1/3/08lU*tEXtSoftwareAdobe Fireworks CS3F&IDATx{T՝?YUb7-F 1x5ҀI&fM̺+YsQI"IF&1Bx!6쮪Su}~t5תo=ۿ>E.@Q"""""""""""""""""""""""".5?"IR>~ pGt@r 6`}6z*w>wkI|0pЭ,P WCk( 4>[8p h<޴vk"ACj:wUa*uSNTUSyg[ԩS>uqi=B*U7Q|A-7R#)B|_UUݧ/wdYFUU$‡<8',}{پ}q] e0pu],pt|9xB\ӪUU%(>q]t:8@s '_g`0 \ hCmr@xx|̘V,r뺎eY$zcnmk hxnʞ;z6,~|$ZSn~~}UՈHI3_#+vkv/:< WnjWٳH8BII pEٓ3 0;6׺k f?ڿe%Se>zVV2fJ`6PԿԡ3D~kjkiF4J$AQ$Ij4MneYwY@w5j2#B4E$24ɡ ,5kɤ$2O -5ipe5j<tη;_qCoMՈQBzu- yWN `gdLd"me!JKĘ@+2 =vq2I4ES5~; t (=z.LP($:7u.YL")L[5k]2 ,A8,3ʃ 0>mz Pdѣ٪tzN0˶lD2Ŋ+6!»}k|t:M"IJ-P컦Mw>W ?>|x=EHa@t~;X+ĀrI8ҥ@,m5wkּ{Ӂ;3i(SWWG+ .)ܻz.z660`PG{Ey ܔÇ?1Pd۲,T"Iuzf OXdc2 w` dYn>kO<ݻqN&!b,0v@y `Ni7DQTU̹,Y_k+ ;/3i1A#"AiWA}3ϟ#TEQYYi7 6䥜t%jEF4$ l;mg}7~H0̏yop V(2S] ?y'O= Oy@TM#bD@0iMm{>pVr!?~ի|3&HbYgpSOOߎ '6pɒ%8 #FUӸy@; jU@jYFUT$u|c@kw`*a LD" ,A6N 3mtv0۹s':** mɗCJJJB_ngzCիWed00 e Ӧ=B߾}; ~m=X_f[.O7C]۸޽`x x;D2m91APπ~!>>"I.=z=a.]:#Hx0|D/y)/υߎ^2]$XE(gdEG:${qliIÈi]tqA OЫȲh[|rs?O/oWZ4D+c(-),w$&ȑ#cHH,+T_">s8ym9Z 0K ,AI<,?A{#v%mV M8ɤ݁:P^QѭU~JIro `S2l1 @Q0zjАv5t#r4MCV1/js^x(0bx`%Cԯп3 .Tt^]*?M-!x̢sXYf AP^_SzAXIQ$!bM H¨#xiĀCFtMCBu\|g3׭iO <_8i3H:wMqtЉܵ{άY/1шe2"Q19r$x!h:%߬Au"F4H'ׯq3֭}DZthEVQAEEpy Tsv͙i$ 9 qQF0iCz[5"vFI8{lݺ Drl+LoUYV4q"munN3v3sJpeD S!I{=&5ִ{7bٲ )1ʀ:q^`Xh YZ ,%5I AvKch=xo qXl9HN嫮q㦌&m C'OGp_(;w͙9sVv,Y4z(&Aw${]׈FŴҶml[q "!!_+M&hҥ؎C4){ڀpu'p}FТ 1sf6ǰ1ؚ"Vִ$3j(&ORo|Kc0z(LqXt)~pNyQGSy޲|dĹ9=,aH8+OIT3v3c`)9EcCc`C"ˌ5BpP]V]Ո۲3|c޼,Cy3+r-^d2Wz.ѨaDѣ;'M~NL8GA܌Yوacc"+lpQ<8yb^gEQèm[$IaɒeX~K|Qu9'oΛg5}Mi*=~n|ڑiBKvyKXP` /|<छF6^hF4A L6SǛYLDU5[,˞W^},s]qK8(|ib+,2iL$HabX{fD h4jx+W,{.%_?tQW:p1l!L:.FDb?GD ˮ$9ggy>ppW]ՉÈ:.d v,_⺹&uXc#݃jiUSJF Jc<$=|+l߱sγ=ϧRI|#UU0&=f=< ?Wڐ& /4+p]p`J(}?]boݮ;ww֠!m~dADܽ*#n2lO09|E4nr:${&Ge4UNE$LO=G}o_{޳ h?;eTx{*tAlyz<6Arao~)w$;J 8ݬuǷ>XtDo9ӋQ[un ]w;/Mj 穩zWr;wlY5?nREP` ʁt]?Odrus_lN}O(tJco7n }zne/󹑽pb_><ہkI(q M0\n5\yj9n`֬YM,k'"{w.RS{-E(p 1 UzJC=+{ҭ";ѽ;ݻwk#G#l޼ǎq 54fՈM /p4VG\pU FEtP8n@tl?§Gl:Ȫ]7mK@U21"j؏RY N,)/Pԕ(cUUUUUUUUUUUUUUUUUUUUU@2vH WIENDB`!! MSBAML```D@AdWindows, Version=2.1.0.0, Culture=neutral, PublicKeyToken=nullF1clr-namespace:Autodesk.Windows;assembly=AdWindowsAutodesk.WindowsEAAcWindows, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nullA%clr-namespace:Autodesk.AutoCAD.RibbonAutodesk.AutoCAD.RibbonRNWindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35WSPresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35^ZWindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\XPresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 RadioButtonImageSourceHDrawing BrushGeometry Rect @Center@RadiusX@RadiusY Pen >Brush > Thickness("Autodesk.Windows.RibbonSplitButton IPEColumnsMenu!Autodesk.Windows.RibbonItem ToolTip71Autodesk.Private.Windows.ToolTipResolverConverter'!Autodesk.Windows.RibbonListButton ListButtonStyle ListStyle ItemsmCommandmInputGestureText IPENumberingMenum IsCheckable IPESpacingMenu IPEEditFieldMenuItem IPEUpdateFieldMenuItem IPEConvertFieldMenuItem IPEInsertFieldMenuItem ConvertCustomMenuItem ! IPEParagraphAlignmentMenuItem  IPEParagraphMenuItem  IPENumberingMenuItem  IPEColumnsMenuItem # IPERemoveParaFormattingMenuItem "IPERemoveAllFormattingMenuItem IPENewFeatureMenuItem IPEWipeOutMenuItem IPEStackMenuItem IPEUnStackMenuItem IPEStackProperty IPEOpaqueBackgroundMenuItem IPEShowRulerMenuItem IPEShowToolbarMenuItem IPESymbolMenuItem IPEImportTextMenuItem IPEFindMenuItem IPEChangeCaseMenuItem Tag IPEAutoCAPSMenuItem IPECharSetMenuItem IPECombinParaMenuItem IPERemoveFormattingMenuItem IPEEditSettingsMenuItem  IPELearnHelpMenuItemF9http://schemas.microsoft.com/winfx/2006/xaml/presentation8x,http://schemas.microsoft.com/winfx/2006/xaml9adw1clr-namespace:Autodesk.Windows;assembly=AdWindows-src%clr-namespace:Autodesk.AutoCAD.RibbonResourceDictionary_1%%& & & & j&  &  & ] &  & 3 & & & 2 & f & &  & r &  & H& & & E& & & q& & & v& & & A& & & HHDrawingImage_3IDrawingGroup_3.GeometryDrawing_5 RectangleGeometry_3$ 0,0,100,100GeometryDrawing_6 @PathGeometry_3$ 50,50&$50Q$50Q> Pen_3 $ 1Qadw:RibbonMenuItem_1$ Columns$ Menu=$ List=. msystem:MenuItem_1$ No Columns$0*src:IPEColumnsMenuHandler.NoColumnsExecutemsystem:MenuItem_2$Dynamic Columnsmsystem:MenuItem_3$Static Columns.@msystem:MenuItem_4$ More...$82src:IPEColumnsMenuHandler.MoreStaticColumnsExecute Separator_1msystem:MenuItem_5$Insert Column Break$82src:IPEColumnsMenuHandler.InsertColumnBreakExecute$ Alt+Enter Separator_2msystem:MenuItem_6$Column Settings...$5/src:IPEColumnsMenuHandler.ColumnSettingsExecuteadw:RibbonMenuItem_2$ Numbering$ Menu=$ List=. msystem:MenuItem_7$ Off$5/src:IPENumberingMenuHandler.NumberingOffExecutemsystem:MenuItem_8$Numbered$:4src:IPENumberingMenuHandler.NumberingNumberedExecutemsystem:MenuItem_9$Lettered.@msystem:MenuItem_10$ Lowercase$C=src:IPENumberingMenuHandler.NumberingLetteredLowercaseExecutemsystem:MenuItem_11$ Uppercase$C=src:IPENumberingMenuHandler.NumberingLetteredUppercaseExecutemsystem:MenuItem_12$Bulleted$:4src:IPENumberingMenuHandler.NumberingBulletedExecute Separator_3msystem:MenuItem_13$ Start$71src:IPENumberingMenuHandler.NumberingStartExecutemsystem:MenuItem_14$Continue$:4src:IPENumberingMenuHandler.NumberingContinueExecute Separator_4msystem:MenuItem_15$Allow Auto-list.$:4src:IPENumberingMenuHandler.NumberingAutoListExecutemsystem:MenuItem_16$Use Tab Delimiter Only.$@:src:IPENumberingMenuHandler.NumberingUseTabDelimterExecutemsystem:MenuItem_17$Allow Bullets and Lists.$93src:IPENumberingMenuHandler.NumberingEnabledExecuteadw:RibbonMenuItem_3$ Line Spacing$ Menu=$ List=. msystem:MenuItem_18$ More...$:4src:IPELineSpacingMenuHandler.MoreLineSpacingExecute Separator_5msystem:MenuItem_19$Clear Line Space$;5src:IPELineSpacingMenuHandler.ClearLineSpacingExecutem MenuItem_4$ Edit Field...$0*src:IPEOptionsMenuHandler.EditFieldExecute$ Ctrl+Fm MenuItem_5$ Update Field$2,src:IPEOptionsMenuHandler.UpdateFieldExecutem MenuItem_6$Convert Field To Text$3-src:IPEOptionsMenuHandler.ConvertFieldExecutemsystem:MenuItem_20$Insert Field...$2,src:IPEOptionsMenuHandler.InsertFieldExecute$ Ctrl+Fm MenuItem_7$Convert Dimension To Text$4.src:IPEOptionsMenuHandler.ConvertCustomExecutemsystem:MenuItem_23$Paragraph Alignmentmsystem:MenuItem_24$ Paragraph...$0*src:IPEOptionsMenuHandler.ParagraphExecutemsystem:MenuItem_25$Bullets and Listsmsystem:MenuItem_37$ Columnsm MenuItem_2$!Remove Paragraph Formatting$@:src:IPEOptionsMenuHandler.RemoveParagraphFormattingExecutem MenuItem_3$Remove All Formatting$:4src:IPEOptionsMenuHandler.RemoveAllFormattingExecutemsystem:MenuItem_63$New Features Workshop$2,src:IPEOptionsMenuHandler.NewFeaturesExecutemsystem:MenuItem_52$Background Mask...$5/src:IPEOptionsMenuHandler.BackgroundMaskExecutem MenuItem_8$ Stack$,&src:IPEOptionsMenuHandler.StackExecutem MenuItem_9$ UnStack$.(src:IPEOptionsMenuHandler.UnStackExecutem MenuItem_10$Stack Property$4.src:IPEOptionsMenuHandler.StackPropertyExecutem MenuItem_11$Opaque Background$71src:IPEOptionsMenuHandler.OpaqueBackgroundExecutemsystem:MenuItem_57$ Show Ruler.$0*src:IPEOptionsMenuHandler.ShowRulerExecutem MenuItem_12$ Show Toolbar.$2,src:IPEOptionsMenuHandler.ShowToolbarExecutemsystem:MenuItem_21$ Symbolmsystem:MenuItem_22$Import Text...$1+src:IPEOptionsMenuHandler.ImportTextExecutemsystem:MenuItem_44$Find and Replace...$5/src:IPEOptionsMenuHandler.FindAndReplaceExecute$ Ctrl+Rmsystem:MenuItem_45$ Change Case$IPEChangeCaseMenuItem.@msystem:MenuItem_46$ UPPERCASE$60src:IPEOptionsMenuHandler.ChangeCaseUpperExecute$ Ctrl+Shift+Umsystem:MenuItem_47$ lowercase$60src:IPEOptionsMenuHandler.ChangeCaseLowerExecute$ Ctrl+Shift+Lmsystem:MenuItem_48$AutoCAPS.$/)src:IPEOptionsMenuHandler.AutoCAPSExecutemsystem:MenuItem_49$ Character Setmsystem:MenuItem_50$Combine Paragraphs$82src:IPEOptionsMenuHandler.CombineParagraphsExecutemsystem:MenuItem_51$Remove Formatting$!IPERemoveFormattingMenuItem.@m MenuItem_1$!Remove Character Formatting$?9src:IPEOptionsMenuHandler.RemoveCharaterFormattingExecute$ Ctrl+Spacemsystem:MenuItem_53$Editor Settings$IPEEditSettingsMenuItem.@msystem:MenuItem_54$Always Display as WYSIWYG.$.(src:IPEOptionsMenuHandler.WYSIWYGExecutesystem:Separator_5msystem:MenuItem_58$Check Spelling.$4.src:IPEOptionsMenuHandler.CheckSpellingExecutemsystem:MenuItem_59$ Check Spelling Settings...$<6src:IPEOptionsMenuHandler.CheckSpellingSettingsExecutemsystem:MenuItem_60$Dictionaries...$3-src:IPEOptionsMenuHandler.DictionariesExecutesystem:Separator_6msystem:MenuItem_61$Text Highlight Color...$4.src:IPEOptionsMenuHandler.TextHighlightExecutemsystem:MenuItem_62$Learn about MTEXT.@msystem:MenuItem_64$ Help$+%src:IPEOptionsMenuHandler.HelpExecute$F1! MSBAML```OKmscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e0891&clr-namespace:System;assembly=mscorlibSystemRNWindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35WSPresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35^ZWindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\XPresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35MergedDictionaries SourceF9http://schemas.microsoft.com/winfx/2006/xaml/presentation8x,http://schemas.microsoft.com/winfx/2006/xaml1system&clr-namespace:System;assembly=mscorlibResourceDictionary_1 ResourceDictionary_3$IPEMenuResource.xaml?ResourceDictionary_4$FrameworkResource.xaml? %!fhFh   ( rc^fffxhb~lfuqfvsiyvn{xr}zu~zqkvo|zsw~|ΩԮžĠƤʪ̭ϲҶӹռ@,>>:,642,...,.? . ,@ 6# .@%+(! .A&/+#! . ,@:72($"2A-?:7/(#2AA?>:2+(6,A'AA@@?72/7( fffffffffffffffffffffffffffffffffffffffffffffffffffԮ}zu{xrzworc^vsiuqf|ԮĠžžԮfffԮԮrc^~lfvoqkrc^xhbΩԮԮԮԮԮfffԮ~zږwyvnռԮ̭ǥžԮfffԮ|rc^ԮϳʫƤԮfffԮ~rc^ԮӹϱʪԮfffԮԮrc^vozsԮԮԮԮԮԮԮԮfffԮԮԮֽҶԮfffԮԮԮռԮfffԮԮԮԮfffԮԮ~lgΩԮԮԮԮԮԮԮԮԮԮfffԮԮԮԮfff( @yhxq{tuwzz}ЫԮž ĠĢƥȧȨɩˬ̮ķ»¼ľγαгдҷӸԺռ׾ؿ\iifRdd__R]]]]RTTTTRTTTTRTTTT:_ ---)----)---T:_  11--)----)---T:d  421-)----)---T)))))))))))))))RGi]]UJ =)7722)----)---THh`]] 0C)=672)----)---THh``8MC)@=63)2---)---TInd]MMM)C@66)2---)---T)))))))))))))))))))RHn L]]QQ)FC@@)722-)---TIn  (]UUU)MFCC)7722)---THn K)`^]U)MMMC)=672)---TIn 'f)``]U)UMMD)@=63)2--T)())))))))))))))))))))RIn  Snh)fd``)]QQM)D@@=)72-THn ,nnl)idd`)]UUM)MC@@)722TIn lnnn)hid`)]U]U)MMD@)733]In nnnn)hhid)`ZUU)MMDD)=63U)))))))))))))))))))))))))RIn"l)nnnn)nnhh)d``Z)UQMM)C@=]Hn\n)nnnn)nnnh)fd``)]QQM)D@@]Innn)nnnn)nnnl)idd`)]UUQ)MC@_&IIIHIHIIIIHGG::++++%%#_( @ yhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhyhϋyh»ڛxqxq|zwuxqžžžԮžžžžԮžžžϋyhýݜxqxq~|zw{t¢ĠžžԮžžžžԮžžžϋyhĿរxqxq~{yȨƤàžԮžžžžԮžžžϋyhԮxqxqxqzxqxqxqԮԮԮԮԮԮԮԮԮԮԮԮԮԮыyh蠜xqÒ{tγԮͯʪǦŢԮžžžžԮžžžϋyh롞xqҭxqԺԮϲ̮ʪǦԮžžžžԮžžžϋyhxqķxqֽԮѵϱ̭ɩԮġžžžԮžžžϋyh򣠜xqآxqԮӹѴαˬԮƤàžžԮžžžϋyhԮxqxqxqԮxqxqxqԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮыyhxqϠԮؿջҷгԮʫȧţŸԮžžžϋyhxqЫԮ׿ջҷԮͯʪǦŢԮžžžϋyhxqԮԮ׾ԺԮϲ̮ʪǦԮžžžϋyhxqԮԮֽԮѵα̭ɩԮġžžϋyhԮxqxqxqxq{tЫԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮыyhxqԮԮԮռӸдͰԮȨƤßϋyhxqԮԮԮ׿ջҷгԮʫȧţϋyh{tԮԮԮ׾ջҷԮͮʪǦыyhԮԮԮ׾ԺԮϲ̮ɩҋyhԮxqԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮԮыyhԮԮԮԮԮӸѴΰ֋yhԮԮԮԮԮռӸд؋yhԮԮԮԮԮ׿ջҷًyhǶǶƶľ¼¾ۋyh! MSBAML```RNWindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35R8clr-namespace:System.ComponentModel;assembly=WindowsBaseSystem.ComponentModelOKmscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e0891&clr-namespace:System;assembly=mscorlibSystemD@AdWindows, Version=2.1.0.0, Culture=neutral, PublicKeyToken=nullF1clr-namespace:Autodesk.Windows;assembly=AdWindowsAutodesk.WindowsX:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindowsAutodesk.Internal.WindowsEAAcWindows, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nullA%clr-namespace:Autodesk.AutoCAD.RibbonAutodesk.AutoCAD.RibbonA=acmgd, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nulljAclr-namespace:Autodesk.AutoCAD.ApplicationServices;assembly=acmgd$Autodesk.AutoCAD.ApplicationServices\:clr-namespace:Autodesk.AutoCAD.Windows.Data;assembly=acmgdAutodesk.AutoCAD.Windows.DataC?acdbmgd, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nullf@clr-namespace:Autodesk.AutoCAD.DatabaseServices;assembly=acdbmgd!Autodesk.AutoCAD.DatabaseServicesR6clr-namespace:Autodesk.AutoCAD.Colors;assembly=acdbmgdAutodesk.AutoCAD.ColorsWSPresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35^ZWindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\XPresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35MergedDictionaries SourceF9http://schemas.microsoft.com/winfx/2006/xaml/presentation8x,http://schemas.microsoft.com/winfx/2006/xaml@scm8clr-namespace:System.ComponentModel;assembly=WindowsBase1System&clr-namespace:System;assembly=mscorlib9adw1clr-namespace:Autodesk.Windows;assembly=AdWindowsCadiw:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindows-acr%clr-namespace:Autodesk.AutoCAD.RibbonKacmgdAclr-namespace:Autodesk.AutoCAD.ApplicationServices;assembly=acmgdCdata:clr-namespace:Autodesk.AutoCAD.Windows.Data;assembly=acmgdGdb@clr-namespace:Autodesk.AutoCAD.DatabaseServices;assembly=acdbmgdAcolors6clr-namespace:Autodesk.AutoCAD.Colors;assembly=acdbmgdResourceDictionary_1 ResourceDictionary_3$4./AcWindows;component/Ribbon/Controls/Base.xaml?ResourceDictionary_4$<6/AcWindows;component/Ribbon/Controls/GalleryCombo.xaml?ResourceDictionary_5$<6/AcWindows;component/Ribbon/Controls/MiscControls.xaml?ResourceDictionary_6$IC/AcWindows;component/Ribbon/Controls/SectionPlaneContextualTab.xaml?ResourceDictionary_7$71/AcWindows;component/Ribbon/Controls/Sliders.xaml?ResourceDictionary_8$GA/AcWindows;component/Ribbon/Controls/SystemVariableDropDowns.xaml?ResourceDictionary_9$GA/AcWindows;component/Ribbon/Controls/TableCellsContextualTab.xaml?ResourceDictionary_10$GA/AcWindows;component/Ribbon/Controls/TextEditorContextualTab.xaml?ResourceDictionary_11$=7/AcWindows;component/Ribbon/Controls/ToggleButtons.xaml?ResourceDictionary_12$F@/AcWindows;component/Ribbon/Controls/UnderlayContextualTabs.xaml? %!A MSBAML```RNWindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35R8clr-namespace:System.ComponentModel;assembly=WindowsBaseSystem.ComponentModelOKmscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e0891&clr-namespace:System;assembly=mscorlibSystemD@AdWindows, Version=2.1.0.0, Culture=neutral, PublicKeyToken=nullF1clr-namespace:Autodesk.Windows;assembly=AdWindowsAutodesk.WindowsX:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindowsAutodesk.Internal.WindowsEAAcWindows, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nullA%clr-namespace:Autodesk.AutoCAD.RibbonAutodesk.AutoCAD.RibbonA=acmgd, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nulljAclr-namespace:Autodesk.AutoCAD.ApplicationServices;assembly=acmgd$Autodesk.AutoCAD.ApplicationServices\:clr-namespace:Autodesk.AutoCAD.Windows.Data;assembly=acmgdAutodesk.AutoCAD.Windows.DataC?acdbmgd, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nullf@clr-namespace:Autodesk.AutoCAD.DatabaseServices;assembly=acdbmgd!Autodesk.AutoCAD.DatabaseServicesR6clr-namespace:Autodesk.AutoCAD.Colors;assembly=acdbmgdAutodesk.AutoCAD.ColorsWSPresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35^ZWindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\XPresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 Short0 Short1 Short2 Short3 Short4 Short5 Short6 Short7 Short8 Short9  ToolTipMaxWidth  StringByEntity  LayerStateComboItemUnsv  ViewItemUnsv  CurrentVS Varies0*Autodesk.AutoCAD.DatabaseServices.ObjectId  NullObjectId  booleanTrue  booleanFalse GalleryDropDownWidth("Autodesk.Windows.RibbonSplitButton AcRibbonSplitButton,&Autodesk.Windows.RibbonChecklistButton AcRibbonChecklistButton& Autodesk.Windows.RibbonSeparator AcRibbonSeparator1+Autodesk.AutoCAD.Ribbon.RibbonCommandButton AcRibbonCommandButton)#Autodesk.Windows.RibbonToggleButton AcRibbonCommandToggleButton5/Autodesk.AutoCAD.Ribbon.RibbonDataBoundDropDown RibbonDataBoundDropDown"Autodesk.Windows.RibbonLabel  AcRibbonLabel!Autodesk.Windows.RibbonItem Text AcRibbonMenuButton' !Autodesk.Windows.RibbonPanelBreak AcRibbonPanelBreak AcRibbonEmptyRowAligner Name HeightSeparatorStyle Tag< 6Autodesk.AutoCAD.Ribbon.GreaterThanOneBooleanConverter greaterThanOneConverter8 2Autodesk.AutoCAD.Ribbon.EqualToOneBooleanConverter equalToOneConverter2 ,Autodesk.AutoCAD.Ribbon.LockedObjectsChecker  lockedObjectsChecker% Autodesk.Windows.RibbonMenuItem !AcRibbonMenuItemSelectColorsIsToolTipEnabled("Autodesk.Windows.RibbonCommandItemCommandHandlerBinding60Autodesk.AutoCAD.ApplicationServices.Application UIBindings Source Path4.Autodesk.AutoCAD.Ribbon.NullToBooleanConverter "nullToBooleanConverter4.Autodesk.AutoCAD.Windows.Data.ReplaceConverter #nullToVariesConverter  SourceValue  TargetValue $booleanToVisibilityConverter %idNullToVisibilityConverter  Converter60Autodesk.AutoCAD.Windows.Data.CompositeConverter  Converters ResourceKey &nullToVisibilityConverter5/Autodesk.AutoCAD.Windows.Data.StandardConverter 'shortToBooleanConverter SourceType TargetTypeJDAutodesk.AutoCAD.Ribbon.SystemVariableToRibbonCommandButtonConverter 0(,systemVariableToRibbonCommandButtonConverterGAAutodesk.AutoCAD.Ribbon.PositiveSystemVariableToIsEnableConverter -))positiveSystemVariableToIsEnableConverterQKAutodesk.AutoCAD.Ribbon.PositiveAndNotZeroSystemVariableToIsEnableConverter 7*3positiveAndNotZeroSystemVariableToIsEnableConverterE?Autodesk.AutoCAD.Ribbon.NonZeroSystemVariableToBooleanConverter ++'nonZeroSystemVariableToBooleanConverter ,int16ToStringConverter;5Autodesk.AutoCAD.Ribbon.ValueToAbsoluteValueConverter !-valueToAbsoluteValueConverter ".int16ToAbsoluteDoubleConverter /nullToVariesStringConverter93Autodesk.AutoCAD.Windows.Data.SourceToTypeConverter 0int16ToLineWeightConverter SourceType ConverterType2,Autodesk.AutoCAD.DatabaseServices.LineWeight 1int16ToDoubleConverter;5Autodesk.AutoCAD.Windows.Data.DoubleToStringConverter 2doubleToStringConverter71Autodesk.AutoCAD.Windows.Data.EnumSubsetConverter 3enumSubsetToBooleanConverter93Autodesk.AutoCAD.Windows.Data.MultiReplaceConverter 4valueToNamedValueConverterFiltersDefaultConverter>8Autodesk.AutoCAD.Windows.Data.ValueToNamedValueConverterD>Autodesk.AutoCAD.Windows.Data.PlotStyleNameToDataItemConverter $5 plotStyleNameToDataItemConverter6 0Autodesk.AutoCAD.Ribbon.Nav3DLensLengthConverter 6nav3DLensLengthConverter5!/Autodesk.AutoCAD.Ribbon.LightsMidTonesConverter 7lightsMidTonesConverter1"+Autodesk.AutoCAD.Ribbon.LightsDateConverter 8lightsDateConverter1#+Autodesk.AutoCAD.Ribbon.LightsTimeConverter 9lightsTimeConverter4$.Autodesk.AutoCAD.Ribbon.Nav3DStepSizeConverter :nav3DStepSizeConverter/%)Autodesk.AutoCAD.Ribbon.Nav3DFOVConverter ;nav3DFOVConverter5&/Autodesk.AutoCAD.Ribbon.TextStyleImageConverter <textStyleImageConverter7'1Autodesk.AutoCAD.Ribbon.VisualStyleImageConverter =visualStyleImageConverter4(.Autodesk.AutoCAD.Ribbon.LineTypeImageConverter >lineTypeImageConverter6)0Autodesk.AutoCAD.Ribbon.LineWeightImageConverter ?lineWeightImageConverter9*3Autodesk.AutoCAD.Windows.Data.RenderPresetConverter @renderPresetConverter6+0Autodesk.AutoCAD.Windows.Data.CellStyleConverter AcellStyleConverter6,0Autodesk.AutoCAD.Ribbon.LockUIToBooleanConverter BlockUIToBooleanConverter:-4Autodesk.AutoCAD.Ribbon.MultiValueToBooleanConverter CmultiValueToBooleanConverter DcolorToNamedValueConverter>.8Autodesk.AutoCAD.Windows.Data.ColorToNamedValueConverter2/,Autodesk.AutoCAD.Ribbon.AddNewColorConverter EsysvarToColorConverter30-Autodesk.AutoCAD.Windows.Data.ColorCollection0ExtraColorItem#1Autodesk.AutoCAD.Colors.Color FsysvarToLineWeightConverter12+Autodesk.AutoCAD.Ribbon.ColorImageConverter GcolorImageConverter HlayerStateItemConverter IviewItemConverterK3EAutodesk.AutoCAD.Ribbon.UcsIconVariableToRibbonCommandButtonConverter 1J-ucsIconVariableToRibbonCommandButtonConverter KvisualStyleConverter LAnnotativeImage UriSource M dataTemplate NbyLayerColorImageBinding Converter ObyLayerLineTypeImageBinding !PbyLayerLineWeightImageBinding "QAcGalleryColorItemDataTemplate Orientation NameTriggers ValueBinding TargetName ValueProperty .R*AcGalleryColorSelectionBoxItemDataTemplate Name S mFontName !Source"SortDescriptions+4%System.ComponentModel.SortDescription#4 PropertyName TexObjectColors$4 Direction25,Autodesk.AutoCAD.Ribbon.FilterableCollection U objectColors%5 FilteredItems(6"Autodesk.AutoCAD.Ribbon.FilterItem &6Value V ObjectColorsF9http://schemas.microsoft.com/winfx/2006/xaml/presentation8x,http://schemas.microsoft.com/winfx/2006/xaml@scm8clr-namespace:System.ComponentModel;assembly=WindowsBase1System&clr-namespace:System;assembly=mscorlib9adw1clr-namespace:Autodesk.Windows;assembly=AdWindowsCadiw:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindows-acr%clr-namespace:Autodesk.AutoCAD.RibbonKacmgdAclr-namespace:Autodesk.AutoCAD.ApplicationServices;assembly=acmgdCdata:clr-namespace:Autodesk.AutoCAD.Windows.Data;assembly=acmgdGdb@clr-namespace:Autodesk.AutoCAD.DatabaseServices;assembly=acdbmgdAcolors6clr-namespace:Autodesk.AutoCAD.Colors;assembly=acdbmgdResourceDictionary_1%"& & & :& W& t& & & & & & "& C& i& & & & *& A& `& & & & & & *& L& s& & & & ^& & & !& "J& #s& $& %770StaticResource_7$nullToBooleanConverter10StaticResource_8$"booleanToVisibilityConverter1& &W0StaticResource_10$nullToBooleanConverter10StaticResource_11$"booleanToVisibilityConverter1& '& (& )& *T& +& ,& -& .(0StaticResource_14$#valueToAbsoluteValueConverter1& /}7& 0& 1& 2 & 31 & 4^ 7#& 5 & 6 & 7A & 8k & 9 & : & ; & < & =. & >Z & ? & @ & A & B & C$ & DP 7#& E! 7 0StaticResource_1$ colorToNamedValueConverter1& F 0StaticResource_2$ int16ToLineWeightConverter10StaticResource_3$ valueToNamedValueConverter1& G& H&7 7 74& I7 & J& K7774& Lr& M& N 7G7G& O7>7>& P7?7?& Qv7G7N& R7&7G7N& S& T& U& V System:Short00 System:Short11 System:Short22 System:Short33 System:Short44 System:Short55 System:Short66 System:Short77 System:Short88 System:Short99XSystem:Double_1400QSystem:String_1 BYENTITYsystem:String_74Unsaved Layer Statesystem:String_ViewItemUnsv Unsaved Viewsystem:String_CurrentVS *Current*system:String_Varies *varies* db:ObjectId_1 Boolean_Truetrue Boolean_False falseXSystem:Double_2400Qadw:RibbonSplitButton_1adw:RibbonChecklistButton_1adw:RibbonSeparator_1acr:RibbonCommandButton_1adw:RibbonToggleButton_1!acr:RibbonDataBoundDropDown_1adw:RibbonLabel_1$#Find product and design filesadw:RibbonSplitButton_2 adw:RibbonPanelBreak_1adw:RibbonSeparator_2$("Ribbon Control - Empty Row Aligner$22Q$ Spacer=$ RIBBON !acr:CountToBooleanConverter_1 $ acr:EqualToOneBooleanConverter_1 %!acr:NonEditableSelectionChecker_1 adw:RibbonMenuItem_1$Select Colors....#Z$# Collections.Colors.Commands[]#ribbon:NullToBooleanConverter_1data:ReplaceConverter_18 Z Z"BooleanToVisibilityConverter_1data:ReplaceConverter_148  data:CompositeConverter_10. data:ReplaceConverter_158  Z22data:ReplaceConverter_17 Z data:CompositeConverter_16. 22data:StandardConverter_3""62acr:SystemVariableToRibbonCommandButtonConverter_13/acr:PositiveSystemVariableToIsEnableConverter_1=9acr:PositiveAndNotZeroSystemVariableToIsEnableConverter_12.acr:NoneZeroSystemVariableToBooleanConverter_1data:StandardConverter_4""'#acr:ValueToAbsoluteValueConverter_1data:CompositeConverter_1. data:StandardConverter_1""X2data:ReplaceConverter_168  Z data:SourceToTypeConverter_1""data:StandardConverter_2""X"ribbon:DoubleToStringConverter'#ribbon:EnumSubsetToBooleanConverter data:MultiReplaceConverter_1.data:ReplaceConverter_18  Z%!data:ValueToNamedValueConverter_1+'data:PlotStyleNameToDataItemConverter_1 %!ribbon:Nav3DLensLengthConverter_1!$ ribbon:LightsMidTonesConverter_1" ribbon:LightsDateConverter_1# ribbon:LightsTimeConverter_2$#ribbon:Nav3DStepSizeConverter_1%ribbon:Nav3DFOVConverter_1&$ ribbon:TextStyleImageConverter_1'&"ribbon:VisualStyleImageConverter_1(#ribbon:LineTypeImageConverter_1)%!ribbon:LineWeightImageConverter_1*"ribbon:RenderPresetConverter_1+ribbon:CellStyleConverter_1,#ribbon:LockUIToBooleanConverter-&"acr:MultiValueToBooleanConverter_1 data:MultiReplaceConverter_2.data:ReplaceConverter_28  Zdata:CompositeConverter_2. .%!data:ColorToNamedValueConverter_1/acr:AddNewColorConverter_1 data:MultiReplaceConverter_3.data:ReplaceConverter_38 # Zdata:CompositeConverter_3.  data:SourceToTypeConverter_2""12data:CompositeConverter_4. 222 ribbon:ColorImageConverter_1data:ReplaceConverter_4 Z data:CompositeConverter_5. data:ReplaceConverter_58  Zdata:ReplaceConverter_108 8 data:ReplaceConverter_6 Z data:CompositeConverter_6. data:ReplaceConverter_78  Z%!data:ValueToNamedValueConverter_3373acr:UcsIconVariableToRibbonCommandButtonConverter_1data:ReplaceConverter_11 Z data:CompositeConverter_13. data:ReplaceConverter_128  Zdata:ReplaceConverter_138 8  BitmapImage_1$<6res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_ANNOTATIVE?DataTemplate_1.R TextBlock_1$ NamePriorityBinding_1.& Binding_49#Z$: 4Collections.Selection.CommonProperties.LayerId.Color8 Binding_50#Z$* $Collections.Layers.CurrentItem.Color8PriorityBinding_2.& Binding_51#Z$E ?Collections.Selection.CommonProperties.LayerId.LinetypeObjectId8 Binding_52#Z$5 /Collections.Layers.CurrentItem.LinetypeObjectId8PriorityBinding_3.& Binding_53#Z$? 9Collections.Selection.CommonProperties.LayerId.LineWeight8 Binding_54#Z$/ )Collections.Layers.CurrentItem.LineWeight8DataTemplate_78.R StackPanel_7$ 0,0,0,1q$ Horizontal=$ 200.+ Border_11$1q$1q ._$ mImage Image_125$ None=$ Value8 TextBlock_18$ 2,0,0,0q$ Center=*Name+  DataTrigger_1$ True$ IsByLayer.a Setter_1$ mImage8 DataTemplate_79.R StackPanel_8$ 0,0,0,0q$ Horizontal=$ 300$16.+$ mImageBorder Border_12$1q y$ Value8._$ mImage Image_126$14$14$ Value8 TextBlock_19$ 2,0,0,0q$ Center=*Name+  DataTrigger_2$ True$ IsByLayer.a Setter_2$ mImage8 DataTrigger_3Z.a Setter_3$ mImageBordery$ Collapsed= CollectionViewSource_7!#Z$& Collections.UIFontInfoCollection "4scm:SortDescription_7$ #Name CollectionViewSource_10!#Z$ Collections.Colors "4scm:SortDescription_14$ #IsNone$$ Descending=4scm:SortDescription_23$# IsByLayer$$ Descending=4scm:SortDescription_18$# IsByBlock$$ Descending=4scm:SortDescription_19$ #IsByAci$$ Descending=4scm:SortDescription_22$# HasBookName$$ Descending=4scm:SortDescription_20$# ColorMethod4scm:SortDescription_21$# ColorIndex4scm:SortDescription_15$ #Name 5acr:FilterableCollection_1!#Z$ Collections.Colors "4scm:SortDescription_24$# IsByLayer$$ Descending=4scm:SortDescription_25$# IsByBlock$$ Descending=4scm:SortDescription_26$ #IsByAci$$ Descending=4scm:SortDescription_27$# HasBookName$$ Descending=4scm:SortDescription_28$# ColorMethod4scm:SortDescription_29$# ColorIndex4scm:SortDescription_30$ #Name %6acr:FilterItem_1#&Z CollectionViewSource_11!#Z$ Collections.Colors "4scm:SortDescription_16$# ColorMethod4scm:SortDescription_17$ #Name !۔ MSBAML```RNWindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35R8clr-namespace:System.ComponentModel;assembly=WindowsBaseSystem.ComponentModelOKmscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e0891&clr-namespace:System;assembly=mscorlibSystemD@AdWindows, Version=2.1.0.0, Culture=neutral, PublicKeyToken=nullF1clr-namespace:Autodesk.Windows;assembly=AdWindowsAutodesk.WindowsX:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindowsAutodesk.Internal.WindowsWSPresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35^ZWindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\XPresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35$Autodesk.Windows.RibbonToolTip TT_AcTextStyleCombo("Autodesk.Windows.RibbonToolTipBase HelpTopicCommand TitleContent71Autodesk.Private.Windows.ToolTipResolverConverter TT_AcDimensionStyleCombo TT_AcMultiLeaderStyleCombo TT_AcTableStyleCombo !TT_AcLayerCommandToggleButton TT_AcLayerStateCombo TT_AcPlotStyleCombo TT_LayerControl -)TT_AcLockedLayerFadingCommandToggleButton TT_AcLockedLayerFadingSlider TT_AcLayerFilterComboControl  TT_AcAttmode1  TT_AcAttmode2  TT_AcAttmode0 TT_AcObjectColorCombo TT_AcLinetypeCombo TT_AcLineWeightCombo  TT_AcFrame0  TT_AcFrame1  TT_AcFrame2  TT_AcFrame3  TT_AcUOSNAP0  TT_AcUOSNAP1  TT_AcUOSNAP2 &"TT_AcXRefFadingCommandToggleButton TT_AcXDwgFadingSlider %!TT_AcQuickCalcCommandToggleButton .*TT_AcExternalReferencesCommandToggleButton TT_AcRibbonFindTextControl TT_AcTFontSizeCombo TT_AcViewPortList TT_AcNamedViewControl ' #TT_AcToolPaletteCommandToggleButton &!"TT_AcPropertiesCommandToggleButton )"%TT_AcAuthorPaletteCommandToggleButton +#'TT_AcSheetSetManagerCommandToggleButton '$#TT_AcCommandLineCommandToggleButton ,%(TT_AcMarkupSetManagerCommandToggleButton (&$TT_AcDesignCenterCommandToggleButton -')TT_AcParametersManagerCommandToggleButton 2(.TT_AcDrawingRecoveryManagerCommandToggleButton ")TT_AcRibbonAutodeskSeekControl *TT_AcOpenDrawingsList IsHelpEnabled +TT_AcStatusBarPanesCheckList ,,(TT_AcDrawingStatusBarCommandToggleButton -TT_AcRibbonLockingButton ".TT_AcVisualStyleGalleryControl /TT_AcNav3DLensLengthSlider 0TT_Ac3DNavPointTriplet1 1TT_Ac3DNavPointTriplet2 2TT_AcSubObjSelect0 3TT_AcSubObjSelect1 4TT_AcSubObjSelect2 5TT_AcSubObjSelect3 6TT_AcSubObjSelect4 7TT_AcDefaultGizmoMove 8TT_AcDefaultGizmoRotate 9TT_AcDefaultGizmoScale :TT_AcDefaultGizmoNoGizmo $; TT_AcXRayModeCommandToggleButton "<TT_AcVisualStylesOpacitySlider =TT_AcVsFaceStyle0 >TT_AcVsFaceStyle1 ?TT_AcVsFaceStyle2 @TT_AcVsLightingQuality0 ATT_AcVsLightingQuality1 BTT_AcVsLightingQuality2 CTT_AcVsFaceColorMode0 DTT_AcVsFaceColorMode1 ETT_AcVsFaceColorMode2 FTT_AcVsFaceColorMode3 G TT_AcVsEdges0 H TT_AcVsEdges1 I TT_AcVsEdges2 JTT_AcLightingUnits0 KTT_AcLightingUnits1 LTT_AcLightingUnits2 3M/TT_AcVisualStyleEdgeOverhangCommandToggleButton &N"TT_AcVisualStyleEdgeOverhangSlider 1O-TT_AcVisualStyleEdgeJitterCommandToggleButton $P TT_AcVisualStyleEdgeJitterSlider 5Q1TT_AcVisualStyleSilouetteEdgesCommandToggleButton .R*TT_AcVisualStyleSilouetteEdgesJitterSlider 4S0TT_AcVisualStyleObscuredEdgesCommandToggleButton %T!TT_AcVisualStyleObscuredEdgeColor 8U4TT_AcVisualStyleIntersectionEdgesCommandToggleButton VTT_AcVisualStyleEdgeColor )W%TT_AcVisualStyleIntersectionEdgeColor +X'TT_AcDefaultLightingCommandToggleButton YTT_AcVsShadows0 ZTT_AcVsShadows1 [TT_AcVsShadows2 \TT_AcLightsBrightnessSlider ]TT_AcLightsContrastSlider ^TT_AcLightsMidTonesSlider &_"TT_AcLightGlyphCommandToggleButton %`!TT_AcSunStatusCommandToggleButton "aTT_AcCameraCommandToggleButton bTT_AcSkyStatus0 cTT_AcSkyStatus1 dTT_AcSkyStatus2 eTT_AcLightsDateSlider fTT_AcLightsTimeSlider (g$TT_AcVSMATERIALMODEDataBoundDropDown hTT_AcRenderQualitySlider iTT_AcRenderPresetList jTT_AcRenderDualProgressBar %k!TT_AcRenderOutputFileToggleButton lTT_AcRenderOutputFileTextBox mTT_AcRenderOutputFileButton nTT_AcOutputSizeList $o TT_AcViewCubeCommandToggleButton (p$TT_AcVisualStylesCommandToggleButton 2q.TT_AcAdvancedRenderSettingsCommandToggleButton "rTT_AcLightsCommandToggleButton %s!TT_AcMaterialsCommandToggleButton )t%TT_AcSunPropertiesCommandToggleButton #uTT_AcExportToWhatDropdownButton vTT_AcPageSetupDropdownButton wTT_AcPageSetupButton xTT_AcWindowButton yTT_AcExportDWFX zTT_AcExportDWF {TT_AcExportPDF !|TT_AcUnderlayBrightnessSliderExpandedContent }TT_AcUnderlayFadeSlider ~TT_AcUnderlayContrastSlider TT_AcImageShowImage TT_AcImageTransparencyToggle "TT_AcUnderlayDisplayMonochrome TT_AcDwfOsnapToggleButton TT_AcUnderlayShowUnderlay TT_AcDgnOsnapToggleButton TT_AcPdfOsnapToggleButton TT_AcSmoothMeshConvert0 TT_AcSmoothMeshConvert1 TT_AcSmoothMeshConvert2 TT_AcSmoothMeshConvert3 TT_AcCellStyleCombo TT_AcBackgroundColorCombo TT_AcQATNewButton TT_AcQATOpenButton TT_AcQATSaveButton TT_AcQATUndoButton TT_AcQATRedoButton TT_AcQATPlotButton TT_AcQATMatchPropButton TT_AcQATPublishButton TT_AcQATPlotPrevButton TT_AcQATPropertiesButton TT_AcQATSSMButton TT_AcQATRenderButton %!TT_AcShowDynamicConstraintsButton TT_AcConstraintStatusButton ($TT_AcRibbonCommandButtonViewportJoin "TT_AcBlockVisibilityHideButton "TT_AcBlockVisibilityShowButton $ TT_AcBlockVisibilityStatesButton "TT_AcBlockVisibilityModeButton %!TT_AcTableCellBorderCommandButton $ TT_AcTableRowDeleteCommandButton &"TT_AcTableInsertFieldCommandButton $ TT_AcTableCellMatchCommandButton &"TT_AcTableRowInsBelowCommandButton &"TT_AcTableInsertBlockCommandButton #TT_AcTableCellLinkCommandButton '#TT_AcTableColumnDeleteCommandButton )%TT_AcTableCellUpdateLinkCommandButton )%TT_AcTableColumnInsRightCommandButton ($TT_AcTableColumnInsLeftCommandButton -)TT_AcTableManageCellContentsCommandButton "TT_AcTableUnMergeCommandButton &"TT_AcTableRowInsAboveCommandButton TT_AcViewportCreatePolygonal TT_AcViewportCreateObject  TT_AcUcsIcon1  TT_AcUcsIcon3  TT_AcUcsIcon0F9http://schemas.microsoft.com/winfx/2006/xaml/presentation8x,http://schemas.microsoft.com/winfx/2006/xaml@scm8clr-namespace:System.ComponentModel;assembly=WindowsBase1System&clr-namespace:System;assembly=mscorlib9adw1clr-namespace:Autodesk.Windows;assembly=AdWindowsCadiw:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindowsResourceDictionary_1%y& & & 8& & & & & 3& & y& & & & @& &  & r & > &  & P &  & z & @& & & @& E& & j& & & s& & !& "& #& $2& %& &3& '& (A& )& *|& +& ,& -=& .& /& 0 & 1& 2R& 3& 4 & 5$!& 6!& 7h"& 8 #& 9#& :Z$& ;$& <%& =*&& >&& ?k'& @+(& A(& B)& C*& D+& Ez,& F-& Gw.& H.& Ic/& J/& K0& L>1& M1& N2& O3& P4& Qr5& RC6& S7& T7& U8& V9& We:& XQ;& Y <& Z|<& [<& \_=& ]>& ^>& _O?& `@& a@& bhA& cA& dB& eGC& fC& gD& h!E& iE& jWF& kF& lG& m/H& nH& oNI& pI& qJ& rTK& sK& tgL& uL& v?N& wN& xO& y@P& zQ& {Q& |R& }kS& ~T&  U& pU& FV& V& ]W& W& \X& X& Y& HZ& Z& [& 0\& \& A]& ]& ^& h^& ^& \_& _& `& a& a& b& b& Rc& 5d& re& f& f& Sg& h& h& h& Oi& i& 6j& j& k& wk& k& Rl& l& =m& m& n& o& @q& q& kradw:RibbonToolTip_1$ STYLE$ STYLE$ Text Style$MGProvides a choice of text styles defined in the drawing to make currentadw:RibbonToolTip_2$DIMSTYLE$DIMSTYLE$Dimension Style$RLProvides a choice of dimension styles defined in the drawing to make currentadw:RibbonToolTip_3$ MLEADERSTYLE$ MLEADERSTYLE$Multileader Style$TNProvides a choice of multileader styles defined in the drawing to make currentadw:RibbonToolTip_4$ TABLESTYLE$ TABLESTYLE$ Table Style$NHProvides a choice of table styles defined in the drawing to make currentadw:RibbonToolTip_76$ LAYER$ LAYER$Layer Properties$)#Manages layers and layer propertiesadw:RibbonToolTip_5$ LAYERSTATE$ LAYERSTATE$ Layer State$c]Opens or closes the Layer States Manager that saves, restores, and manages named layer statesadw:RibbonToolTip_115$ PLOTSTYLE$ PLOTSTYLE$ Plot Style$.(Displays and sets the current plot styleadw:RibbonToolTip_6$ LAYER$ LAYER$ Layer$[UProvides a choice of layers and layer settings defined in the drawing to make currentadw:RibbonToolTip_77$LAYLOCKFADECTL$LAYLOCKFADECTL$Locked Layer Fading$F@Turns on or turns off the fading effect applied to locked layersadw:RibbonToolTip_21$LAYLOCKFADECTL$LAYLOCKFADECTL$Locked Layer Fading$@:Controls the amount of fading for objects on locked layersadw:RibbonToolTip_113$ LAYER$ LAYER $ Layer Filters$yProvides a choice of layer filters applied to the list of layers in the Layer Properties Manager and in the Layer controladw:RibbonToolTip_34$ ATTDISP$ ATTDISP$Retain Attribute Display$QKRestores the original visibility of each block attribute, visible or hiddenadw:RibbonToolTip_35$ ATTDISP$ ATTDISP$Display All Attributes$UOMakes all block attributes visible, overriding the original visibility settingsadw:RibbonToolTip_36$ ATTDISP$ ATTDISP$Hide All Attributes$WQMakes all block attributes invisible, overriding the original visibility settingsadw:RibbonToolTip_7$ COLOR$ COLOR$ Object Color$vpProvides a choice of colors to make current if no objects are selected, or changes the color of selected objectsadw:RibbonToolTip_8$LINETYPE$LINETYPE$Linetype$|vProvides a choice of linetypes to make current if no objects are selected, or changes the linetype of selected objectsadw:RibbonToolTip_9$ LWEIGHT$ LWEIGHT$ Lineweight$zProvides a choice of lineweights to make current if no objects are selected, or changes the lineweight of selected objectsadw:RibbonToolTip_37$ FRAME$ FRAME$ Hide frames$4.Hide all DWF, DWFx, PDF, DGN, and image framesadw:RibbonToolTip_38$ FRAME$ FRAME$Display and plot frames$@:Display and plot all DWF, DWFx, PDF, DGN, and image framesadw:RibbonToolTip_39$ FRAME$ FRAME$#Display but don't plot frames$@:Displays underlay frames but keeps them from being plottedadw:RibbonToolTip_40$ FRAME$ FRAME$Frames settings vary$=7Settings for DWF, DWFx, PDF, DGN, and image frames varyadw:RibbonToolTip_41$ UOSNAP$ UOSNAP$Snap to Underlays Off$qkObject snapping is disabled for geometry in all DWF, DWFx, PDF, and DGN underlay attachments in the drawingadw:RibbonToolTip_42$ UOSNAP$ UOSNAP$Snap to Underlays On$pjObject snapping is enabled for geometry in all DWF, DWFx, PDF, and DGN underlay attachments in the drawingadw:RibbonToolTip_43$ UOSNAP$ UOSNAP$Underlay OSnap’s vary$93Settings for DWFOSNAP, PDFOSNAP , and DGNOSNAP varyadw:RibbonToolTip_78$ XDWGFADECTL$ XDWGFADECTL$ Xref Fading$WQTurns on or turns off the fading effect applied to externally referenced drawingsadw:RibbonToolTip_22$ XDWGFADECTL$ XDWGFADECTL$ Xref Fading$Specifies the fading intensity value of externally referenced drawings. This option only affects the display on the screen. It does not affect plotting or plot preview.adw:RibbonToolTip_79$ QUICKCALC$ QUICKCALC$Quick Calculator$.(Opens or closes the QuickCalc calculatoradw:RibbonToolTip_80$EXTERNALREFERENCES$EXTERNALREFERENCES$!External References Palette$.(Displays the External References Paletteadw:RibbonToolTip_117$ FIND$ FIND$ Text Find$XRFinds the text in the drawing that you specify, and can replace it with other textadw:RibbonToolTip_10$TEXTSIZE$TEXTSIZE$Annotation Text Height$VPSets the default height for new text objects created with the current text styleadw:RibbonToolTip_11$ VPORTS$ VPORTS$Viewport Configurations$d^Provides a choice of viewport configurations currently available in model space or paper spaceadw:RibbonToolTip_12$ VIEW$ VIEW$ 3D Navigation$D>Provides a choice of standard views, or opens the View Manageradw:RibbonToolTip_81$ TOOLPALETTES$ TOOLPALETTES$ Tool Palettes$'!Opens or closes the Tool palettesadw:RibbonToolTip_82$ PROPERTIES$ PROPERTIES$Properties Palette$,&Opens or closes the Properties paletteadw:RibbonToolTip_83$BAUTHORPALETTE$BAUTHORPALETTE$Block Authoring Palette$E?Opens or closes the Block Authoring palette in the Block Editoradw:RibbonToolTip_84$SHEETSET$SHEETSET$Sheet Set Manager$+%Opens or closes the Sheet Set Manageradw:RibbonToolTip_85$ COMMANDLINE$ COMMANDLINE$ Command Line$-'Opens or closes the Command Line windowadw:RibbonToolTip_86$ MARKUP$ MARKUP$Markup Set Manager$,&Opens or closes the Markup Set Manageradw:RibbonToolTip_87$ADCENTER$ADCENTER$ DesignCenter$-'Opens or closes the DesignCenter windowadw:RibbonToolTip_88$ PARAMETERS$ PARAMETERS$Parameters Manager$71Displays or hides the constraint variables windowadw:RibbonToolTip_89$DRAWINGRECOVERY$DRAWINGRECOVERY$Drawing Recovery Manager$2,Opens or closes the Drawing Recovery Manageradw:RibbonToolTip_108$ SEEK$ SEEK$ Autodesk Seek$UOSearches the Autodesk Seek Website for content relevant to the keywords enteredadw:RibbonToolTip_107.$Switch Windows$=7Provides a choice of open drawing files to make currentadw:RibbonToolTip_109$ TRAYSETTINGS$ TRAYSETTINGS$Status Bar Options$LFControls the display of icons and notifications in the status bar trayadw:RibbonToolTip_90$ STATUSBAR$ STATUSBAR$Drawing Status Bar$E?Controls the display of the application and drawing status barsadw:RibbonToolTip_110$ LOCKUI$ LOCKUI$Window Locking$RLLocks the position and size of ribbon panels, toolbars, and dockable windowsadw:RibbonToolTip_13$ VISUALSTYLES$ VISUALSTYLES$ Visual Styles$OIProvides a choice of visual styles defined in the drawing to make currentadw:RibbonToolTip_23$ LENSLENGTH$ LENSLENGTH$ Lens Length$3-Adjusts the lens length of a perspective viewadw:RibbonToolTip_111$ CAMERA$ CAMERA$Target Position$QKControls the point of view (position of the camera) in the current viewportadw:RibbonToolTip_112$ CAMERA$ CAMERA$Camera Position$UOControls the target point of the camera (center point) for the current viewportadw:RibbonToolTip_44$SUBOBJSELECTIONMODE$SUBOBJSELECTIONMODE$ No Filter$BNo face style is applied to 3D objects in the current viewportadw:RibbonToolTip_53$ VSFACESTYLE$ VSFACESTYLE$Realistic Face Style$HBApplies a realist face style to 3D objects in the current viewportadw:RibbonToolTip_54$ VSFACESTYLE$ VSFACESTYLE$Warm-Cool Face Style$b\Applies cool and warm colors instead of dark and light to 3D objects in the current viewportadw:RibbonToolTip_55$VSLIGHTINGQUALITY$VSLIGHTINGQUALITY$Facet Lighting$icApplies a single color that computed for each face of a surface or 3D solid in the current viewportadw:RibbonToolTip_56$VSLIGHTINGQUALITY$VSLIGHTINGQUALITY$Smooth Lighting$nhApplies colors that are computed as a gradient between the vertices of the faces in the current viewportadw:RibbonToolTip_57$VSLIGHTINGQUALITY$VSLIGHTINGQUALITY$Smoothest Lighting$Applies colors that are computed for individual pixels if the Per-Pixel Lighting setting is turned on in the Manual Performance Tuning dialog boxadw:RibbonToolTip_58$VSFACECOLORMODE$VSFACECOLORMODE$ Normal$jdDisplays all faces without a face color modifier in the visual style applied to the current viewportadw:RibbonToolTip_59$VSFACECOLORMODE$VSFACECOLORMODE$ Monochrome$Displays all faces in the color that is specified in the VSMONOCOLOR system variable in the visual style applied to the current viewportadw:RibbonToolTip_60$VSFACECOLORMODE$VSFACECOLORMODE$ Tint$Shades all faces by changing the hue and saturation values of the color that is specified in the VSMONOCOLOR system variable in the visual style applied to the current viewportadw:RibbonToolTip_61$VSFACECOLORMODE$VSFACECOLORMODE$ Desaturate$Shades all faces with a softer color by reducing its saturation component by 30 percent in the visual style applied to the current viewportadw:RibbonToolTip_62$No Edges$ VSEDGES$ VSEDGES$,&No edges are displayed in the viewportadw:RibbonToolTip_63$Isolines$ VSEDGES$ VSEDGES$,&Isolines are displayed in the viewportadw:RibbonToolTip_64$ Facet Edges$ VSEDGES$ VSEDGES$/)Facet edges are displayed in the viewportadw:RibbonToolTip_65$Generic lighting units$ LIGHTINGUNITS$ LIGHTINGUNITS$KENo lighting units are used and standard (generic) lighting is enabledadw:RibbonToolTip_66$American lighting units$ LIGHTINGUNITS$ LIGHTINGUNITS$KEAmerican lighting unites are used and photometric lighting is enabledadw:RibbonToolTip_67$"International lighting units$ LIGHTINGUNITS$ LIGHTINGUNITS$OIInternational lighting units are used and photometric lighting is enabledadw:RibbonToolTip_92$VSEDGEOVERHANG.$VSEDGEOVERHANG$ Edge Overhang$Turns on and off the effect that makes edges on 3D solids extend beyond their intersection in the visual style applied to the current viewportadw:RibbonToolTip_32$VSEDGEOVERHANG$VSEDGEOVERHANG$Overhang$Controls the amount of edge overhang that 3D solids extend beyond their intersections in the visual style applied to the current viewportadw:RibbonToolTip_93$ VSEDGEJITTER$ VSEDGEJITTER$ Edge Jitter$yTurns on and off the effect that makes edges on 3D solids appear wavy in the visual style applied to the current viewportadw:RibbonToolTip_25$ VSEDGEJITTER$ VSEDGEJITTER$ Edge Jitter$keControls the amount of edge waviness on 3D solids in the visual style applied to the current viewportadw:RibbonToolTip_94$ VSSILHEDGES$ VSSILHEDGES$Silhouette Edges$wqTurns on and off the display of silhouette edges on 3D solids in the visual style applied to the current viewportadw:RibbonToolTip_26$ VSSILHWIDTH$ VSSILHWIDTH$Silhouette Edge Width$qkControls the width of the silhouette edges on 3D solids in the visual style applied to the current viewportadw:RibbonToolTip_95$VSOBSCUREDEDGES$VSOBSCUREDEDGES$Obscured Edges$yTurns on and off the display of obscured or hidden edges on 3D solids in the visual style applied to the current viewportadw:RibbonToolTip_14$VSOBSCUREDCOLOR$VSOBSCUREDCOLOR$Obscured Edge Color$hbSpecifies the color of obscured (hidden) lines in the visual style applied to the current viewportadw:RibbonToolTip_96$VSINTERSECTIONEDGES$VSINTERSECTIONEDGES$Intersection Edges$ysTurns on and off the display of intersection edges on 3D solids in the visual style applied to the current viewportadw:RibbonToolTip_15$ VSEDGECOLOR.$ VSEDGECOLOR$ Edge Color$f`Controls the color of the edges on 3D solids in the visual style applied to the current viewportadw:RibbonToolTip_16$VSINTERSECTIONCOLOR.$VSINTERSECTIONCOLOR$Edge Instersection Color$smControls the color of the intersection edges on 3D solids in the visual style applied to the current viewportadw:RibbonToolTip_97$DEFAULTLIGHTING$DEFAULTLIGHTING$Default Lighting$ZTTurns on and off default lighting in place of other lighting in the current viewportadw:RibbonToolTip_68$ VSSHADOWS$ VSSHADOWS$ Shadows Off$No shadows are displayedadw:RibbonToolTip_69$ VSSHADOWS$ VSSHADOWS$Ground Shadows$"Displays ground shadows onlyadw:RibbonToolTip_70$ VSSHADOWS$ VSSHADOWS$ Full Shadows$Displays full shadowsadw:RibbonToolTip_27$RENDEREXPOSURE$RENDEREXPOSURE$Light Brightness$HBAdjusts the global brightness for the lighting used when renderingadw:RibbonToolTip_28$RENDEREXPOSURE$RENDEREXPOSURE$Light Contrast$F@Adjusts the global contrast for the lighting used when renderingadw:RibbonToolTip_29$RENDEREXPOSURE$RENDEREXPOSURE$Light Midtones$F@Adjusts the global midtones for the lighting used when renderingadw:RibbonToolTip_98$LIGHTGLYPHDISPLAY$LIGHTGLYPHDISPLAY$Light Glyph Display$ZTTurns on and off the display of glyphs that represent lights in the current viewportadw:RibbonToolTip_99$ SUNSTATUS$ SUNSTATUS$ Sun Status$NHTurns on and off the lighting effects of the sun in the current viewportadw:RibbonToolTip_100$ CAMERADISPLAY$ CAMERADISPLAY$Camera Display$[UTurns on and off the display of glyphs that represent cameras in the current viewportadw:RibbonToolTip_71$ SKYSTATUS$ SKYSTATUS$ Sky Off$?9Turns off the sky illumination computations for renderingadw:RibbonToolTip_72$ SKYSTATUS$ SKYSTATUS$Sky Background$XRTurns on only the sky background for rendering; the sky illumination is turned offadw:RibbonToolTip_73$ SKYSTATUS$ SKYSTATUS$%Sky Background and Illumination$BControls the visibility and display properties of the ViewCubeadw:RibbonToolTip_101$ VISUALSTYLES$ VISUALSTYLES$Visual Styles Manager$zOpens or closes the Visual Styles manager that creates and modifies visual styles and applies a visual style to a viewportadw:RibbonToolTip_102$ RPREF$ RPREF$Advanced Render Settings$:4Opens or closes the Advanced Render Settings paletteadw:RibbonToolTip_103$ LIGHTLIST$ LIGHTLIST$Lights in Model Palette$2,Turns on and off the Lights in Model paletteadw:RibbonToolTip_104$ MATERIALS$ MATERIALS$Materials Palette$+%Opens or closes the Materials paletteadw:RibbonToolTip_105$ SUNPROPERTIES$ SUNPROPERTIES$Sun Properties Palette$2,Displays or hides the Sun Properties paletteadw:RibbonToolTip_118$WHATTOEXPORTCOMBO$What to export$Selects which part of the drawing to export. If you are in paper space, you can select the current layout or all layouts. If you are in model space, you can select the objects currently displayed, the drawing extents, or a selected areaadw:RibbonToolTip_119$PAGESETUPCOMBO$ Page Setup$ysAllows you to export the file using the page setup settings in the Page Setup Manager or to override these settingsadw:RibbonToolTip_120$PageSetupOverrideDialog$ Page Setup$~Allows you to specify settings such as paper size, scale and plot size. Button is not active if you select Page Setup: Currentadw:RibbonToolTip_121$ EXPORTWINDOW$ Window$.(Specify an area to export in Model Spaceadw:RibbonToolTip_122$ EXPORTDWFX$ EXPORTDWFX$ Export$vpCreates a DWF, DWFx, or PDF file and allows you to set individual page setup overrides on a sheet by sheet basisadw:RibbonToolTip_123$ EXPORTDWF$ EXPORTDWF$ Export$vpCreates a DWF, DWFx, or PDF file and allows you to set individual page setup overrides on a sheet by sheet basisadw:RibbonToolTip_124$ EXPORTPDF$ EXPORTPDF$ Export$vpCreates a DWF, DWFx, or PDF file and allows you to set individual page setup overrides on a sheet by sheet basisadw:RibbonToolTip_125$ImgAdjustBrightness$ Brightness$82Controls the brightness, and contrast of the image$\VThe greater the value, the more each pixel is forced to its primary or secondary coloradw:RibbonToolTip_126$ UnderlayFade$ Fade$f`The greater the value, the more the attached reference blends with the current background color.adw:RibbonToolTip_127$UnderlayContrast$Contrast$YSControls the contrast, and indirectly, the fading effect of the attached reference.$\VThe greater the value, the more each pixel is forced to its primary or secondary coloradw:RibbonToolTip_128$ ShowUnderlay$ Show Image$!Hides or displays the imageadw:RibbonToolTip_129$ReferenceOptTransparency$ Transparency$}Turns transparency on so that objects beneath the image are visible and off so that objects beneath the image are not visibleadw:RibbonToolTip_130$UnderlayMonochrome$Display in Monochrome$.(Displays the underlay in black and whiteadw:RibbonToolTip_131$DWFOSNAP$ Enable Snap$SMDetermines whether object snapping is active for geometry in the DWF underlayadw:RibbonToolTip_132$ ShowUnderlay$ Show Underlay$$Hides or displays the underlayadw:RibbonToolTip_133$DGNOSNAP$ Enable Snap$SMDetermines whether object snapping is active for geometry in the DGN underlayadw:RibbonToolTip_134$PDFOSNAP$ Enable Snap$SMDetermines whether object snapping is active for geometry in the PDF underlayadw:RibbonToolTip_135$SMOOTHMESHCONVERT$SMOOTHMESHCONVERT$Smooth, optimized$.(Creates a smooth model that merges facesadw:RibbonToolTip_136$SMOOTHMESHCONVERT$SMOOTHMESHCONVERT$Smooth, not optimized$VPCreates a smooth model with the same number of faces as the original mesh objectadw:RibbonToolTip_137$SMOOTHMESHCONVERT$SMOOTHMESHCONVERT$Faceted, optimized$71Creates an angular model that merges planar facesadw:RibbonToolTip_138$SMOOTHMESHCONVERT$SMOOTHMESHCONVERT$Faceted, not optimized$XRCreates an angular model with the same number of faces as the original mesh objectadw:RibbonToolTip_139$Table Cell Styles.$D>Lists all cell styles contained within the current table styleadw:RibbonToolTip_140$!Table Cell Background Color.$f`Select None or a background color, or click Select Colors to display the Select Color dialog boxadw:RibbonToolTip_141$ QNEW$ QNEW$ New$"Creates a blank drawing fileadw:RibbonToolTip_142$ OPEN$ OPEN$ Open$$Opens an existing drawing fileadw:RibbonToolTip_143$ QSAVE$ QSAVE$ Save$Saves the current drawingadw:RibbonToolTip_144$U$U$ Undo$%Reverses the most recent actionadw:RibbonToolTip_145$ MREDO$ REDO$ Redo$<6Reverses the effects of the previous UNDO or U commandadw:RibbonToolTip_146$ PLOT$ PLOT$ Plot$5/Prints a drawing to a plotter, printer, or fileadw:RibbonToolTip_147$ MATCHPROP$ MATCHPROP$Match Properties$BCombines two adjacent model viewports into one larger viewport TextBlock_1The two model viewports must share a common edge of the same length. The resulting viewport inherits the view of the dominant viewport.adw:RibbonToolTip_156$ BVHIDE$ BVHIDE$Make Invisible$WQMakes objects invisible for the current visibility state or all visibility statesadw:RibbonToolTip_157$ BVSHOW$ BVSHOW$ Make Visible$UOMakes objects visible for the current visibility state or all visibility statesadw:RibbonToolTip_158$ BVSTATE$ BVSTATE$Visibility States$E?Creates, sets, or deletes a visibility state in a dynamic blockadw:RibbonToolTip_159$ BVMODE$ BVMODE$Visibility Mode$uoControls how objects that are made invisible for the current visibility state are displayed in the Block Editoradw:RibbonToolTip_160$ Cell Borders$5/Controls the appearance of the borders of cells.adw:RibbonToolTip_161$ Delete Row(s)$Deletes rows in a table.adw:RibbonToolTip_162$ Insert Field$60Inserts a text field into the current table cell.adw:RibbonToolTip_163$ Match Cell$JDApplies the properties of a selected table cell to other table cells.adw:RibbonToolTip_164$ Insert Below$+%Inserts a row below the selected cell.adw:RibbonToolTip_165$ Insert Block$ Insert Block.adw:RibbonToolTip_166$ Link Cell...$]WEstablishes a link between the data in a table cell with data in a Microsoft Excel file.adw:RibbonToolTip_167$Delete Column(s)$ Deletes columns in a table.adw:RibbonToolTip_168$Download from Source$'!Download changes from source file.adw:RibbonToolTip_169$ Insert Right$82Inserts a column to the right of the selected cell.adw:RibbonToolTip_170$ Insert Left$71Inserts a column to the left of the selected cell.adw:RibbonToolTip_171$Manage Cell Contents...$60Controls the order and direction of cell content.adw:RibbonToolTip_172$ Unmerge Cells$-'Separates previously merged table cells.adw:RibbonToolTip_173$ Insert Above$+%Inserts a row above the selected cell.adw:RibbonToolTip_174$Create Polygonal$ICCreates an irregularly shaped viewport defined by specifying points.$ VPORTS_CLI$ -VPORTS TextBlock_2It is important to create layout viewports on their own layer. When you are ready to plot, you can turn off the layer and plot the layout without plotting the boundaries of the layout viewports.adw:RibbonToolTip_175$ Convert Object to Viewport$icCreates a nonrectangular layout viewport from a closed polyline, ellipse, spline, region, or circle.$ -VPORTS$ VPORTS_CLI TextBlock_3It is important to create layout viewports on their own layer. When you are ready to plot, you can turn off the layer and plot the layout without plotting the boundaries of the layout viewports.adw:RibbonToolTip_177$ UCSICON$ UCSICON$ Show UCS Icon$RLDisplays the UCS Icon either at the origin or at the corner of the viewport.adw:RibbonToolTip_178$ UCSICON$ UCSICON$Show UCS Icon at Origin$/)Displays the UCS Icon at the origin only.adw:RibbonToolTip_176$ UCSICON$ UCSICON$ Hide UCS Icon$Hides the UCS Icon.! MSBAML```RNWindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35R8clr-namespace:System.ComponentModel;assembly=WindowsBaseSystem.ComponentModelOKmscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e0891&clr-namespace:System;assembly=mscorlibSystemD@AdWindows, Version=2.1.0.0, Culture=neutral, PublicKeyToken=nullF1clr-namespace:Autodesk.Windows;assembly=AdWindowsAutodesk.WindowsX:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindowsAutodesk.Internal.WindowsEAAcWindows, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nullA%clr-namespace:Autodesk.AutoCAD.RibbonAutodesk.AutoCAD.RibbonA=acmgd, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nulljAclr-namespace:Autodesk.AutoCAD.ApplicationServices;assembly=acmgd$Autodesk.AutoCAD.ApplicationServices\:clr-namespace:Autodesk.AutoCAD.Windows.Data;assembly=acmgdAutodesk.AutoCAD.Windows.DataC?acdbmgd, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nullf@clr-namespace:Autodesk.AutoCAD.DatabaseServices;assembly=acdbmgd!Autodesk.AutoCAD.DatabaseServicesR6clr-namespace:Autodesk.AutoCAD.Colors;assembly=acdbmgdAutodesk.AutoCAD.ColorsC&clr-namespace:Autodesk.AutoCAD.WindowsAutodesk.AutoCAD.WindowsWSPresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35^ZWindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\XPresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35MergedDictionaries Source sortedTableStyles Source60Autodesk.AutoCAD.ApplicationServices.Application UIBindings Source PathSortDescriptions+%System.ComponentModel.SortDescription PropertyName;5Autodesk.AutoCAD.Ribbon.DimensionCollectionViewSource sortedDimStyles  mleaderStyles  mtextStyles  mVisualStyles  lineTypes  lineWeights  plotStyles  layerStates  namedViews-'System.Windows.Data.CompositeCollection  namedViewsComposite Collection%Autodesk.Windows.RibbonMenuItem!Autodesk.Windows.RibbonItem Name Image93Autodesk.Private.Windows.RibbonImageSourceConverter  LargeImage IsToolTipEnabled("Autodesk.Windows.RibbonCommandItem CommandHandlerBinding  renderPredefinedOutputSizes  renderCustomOutputSizes  renderOutputSizes:4Autodesk.AutoCAD.Ribbon.DataItemCollectionViewSource layers$ Autodesk.Windows.RibbonGallery AcOutputSizeList TT_AcOutputSizeListToolTip DisplayMode Tag! Autodesk.Windows.RibbonList ItemsSourceBinding CurrentBinding Mode ItemTemplate Orientation" Autodesk.Windows.RibbonCombo MenuItems Text AcTableStyleCombo TT_AcTableStyleComboIsEnabledBinding nullToBooleanConverter Converter6 0Autodesk.AutoCAD.Windows.Data.CompositeConverter Converters8 2Autodesk.AutoCAD.Ribbon.DataItemToCommandConverter Command ResourceKey AcDimensionStyleCombo TT_AcDimensionStyleCombo ]Name4.System.Windows.Automation.AutomationProperties AutomationId,&Autodesk.Internal.Windows.ImageAligner Name AnnotativeImage Name!Triggers "Value#Binding$ TargetName%Property &Value AcMultiLeaderStyleCombo TT_AcMultiLeaderStyleCombo AcTextStyleItemDataTemplate textStyleImageConverter' TextAlignment +'AcTextStyleSelectionBoxItemDataTemplate AcTextStyleCombo TT_AcTextStyleCombo( ShowImage) DropDownWidth* SelectionBoxItemTemplate+ ItemTemplateTextBinding, ItemTemplateImageBinding!- ItemTemplateToolTipBinding. ItemTemplateIdBinding AcIPEFontStyleGallery AcBlockVisibilitiesCombo  AcRenderPresetList !TT_AcRenderPresetList "renderPresetConverter #booleanToVisibilityConverter $AcExportDataTemplate %AcPageSetuptDataTemplate #&AcLinetypeComboItemDataTemplate 'lineTypeImageConverter (byLayerLineTypeImageBinding /)+AcLinetypeComboSelectionBoxItemDataTemplate *nullToVisibilityConverter71Autodesk.AutoCAD.Ribbon.PriorityBindingWorkaround +lineTypeBindingBridge /Source ,AcLinetypeCombo -TT_AcLinetypeCombo0MinWidth '.#AcLineweightGalleryItemDataTemplate /lineWeightImageConverter !0byLayerLineWeightImageBinding 31/AcLineweightGallerySelectionBoxItemDataTemplate 2AcLineWeightCombo 3TT_AcLineWeightCombo 4sysvarToLineWeightConverter 5AcObjectColorCombo 6TT_AcObjectColorCombo "7AcGalleryColorItemDataTemplate .8*AcGalleryColorSelectionBoxItemDataTemplate 9 objectColors5/Autodesk.AutoCAD.Ribbon.ColorToCommandConverter :sysvarToColorConverter ;AcVisualStyleEdgeColor <TT_AcVisualStyleEdgeColor =exObjectColors ">AcVisualStyleObscuredEdgeColor %?!TT_AcVisualStyleObscuredEdgeColor &@"AcVisualStyleIntersectionEdgeColor )A%TT_AcVisualStyleIntersectionEdgeColor BAcPlotStyleCombo CTT_AcPlotStyleCombo93Autodesk.AutoCAD.Windows.Data.MultiReplaceConverter1Filters4.Autodesk.AutoCAD.Windows.Data.ReplaceConverter2 SourceValue3 Converter93Autodesk.AutoCAD.Windows.Data.NullToVariesConverter4DefaultConverter $D plotStyleNameToDataItemConverter EAcLayerStateCombo FTT_AcLayerStateCombo GlayerStateItemConverter#Autodesk.Windows.RibbonButton HAcRenderOutputFileButton ITT_AcRenderOutputFileButton5ShowText$Autodesk.Windows.RibbonTextBox JAcRenderOutputFileTextBox KTT_AcRenderOutputFileTextBox6TextValueBinding/)Autodesk.AutoCAD.Ribbon.RibbonTextBoxItem LAcRibbonTextBoxItem MAcVisualStyleGalleryControl "NTT_AcVisualStyleGalleryControl OGalleryDropDownWidth PvisualStyleConverter QvisualStyleImageConverter RidNullToVisibilityConverter SAcNamedViewControl TTT_AcNamedViewControl7 RowsInWindowMode8^ Conditions9Binding :Value UShort1 VShort0 WviewItemConverter XWrapperButtonStyle; TargetType< TargetType YWrapperTextBoxStyle =Name Z Image_LayerOn> UriSource [Image_LayerOff \Image_LayerLocked ]Image_LayerUnlocked ^Image_LayerFrozen _Image_LayerThawed `Image_LayerVpFrozen aImage_LayerVpThawed blayerOffToImage c booleanTrue? TargetValue d booleanFalse elayerFrozenToImage flayerLockedToImage glayerVpFrozenToImage &h"tilemodeToVpFrzVisibilityConverter isysvarToWPFColorConverter93Autodesk.AutoCAD.Windows.Data.SourceToTypeConverter@ SourceTypeA ConverterType#Autodesk.AutoCAD.Colors.Color1+Autodesk.AutoCAD.Windows.AcadColorConverter "jvpOverrideBackgroundColorBrush BColor kLayerOnOffToolTip lLayerFreezeThawAllVPToolTip #mLayerFreezeThatCurrentVPToolTip nLayerLockUnlockToolTip oLayerColorToolTip pVpColorToolTip qlayerBindingBridgeCUpdateSourceTrigger93Autodesk.AutoCAD.Ribbon.FrozenOffLayerObjectChecker,&Autodesk.AutoCAD.Ribbon.LayerValidator r LayerControl sTT_LayerControlD TextPathEColumnDefinitionsFzSharedSizeGroupGToolTipHd IsChecked INameJRelativeSource KMode LName tcolorImageConverterM^InitialShowDelayNP SourceNameOPProperty PPValue uBinding_IsTilemode1 vshortToBooleanConverterQConverterParameter wBinding_IsTilemode0 xAcViewports_Active yTT_AcViewPortList zAcViewports_Single {AcViewports_TwoVertical |AcViewports_TwoHorizontal }AcViewports_ThreeRight ~AcViewports_ThreeLeft AcViewports_ThreeAbove AcViewports_ThreeBelow AcViewports_ThreeVertical AcViewports_ThreeHorizontal AcViewports_FourEqual AcViewports_FourRight AcViewports_FourLeft("Autodesk.Windows.RibbonSplitButton AcViewPortList'!Autodesk.Windows.RibbonListButtonRIsSplit$SIsSynchronizedWithCurrentItem TItems AcCreateViewportDropdown TT_AcViewportCreatePolygonal TT_AcViewportCreateObject AcTFontSizeCombo TT_AcTFontSizeComboU IsEditable AcExportEplotCombo #TT_AcExportToWhatDropdownButton AcExportPageSetupCombo TT_AcPageSetupDropdownButton namedUCSPlanes AcMenuItemUCSTop AcMenuItemUCSBottom AcMenuItemUCSLeft AcMenuItemUCSRight AcMenuItemUCSFront AcMenuItemUCSBack AcMenuItemUCSWorld AcMenuItemUCSUnnamedV IsVisible ucsPlaneConverter4.Autodesk.AutoCAD.Windows.Data.StandardUcsPlane WWorld XTop YBottom ZLeft [Right \Front ]Back^Unnamed namedUCSPlanesComposite&  Autodesk.Windows.RibbonSeparator ($AcUCSPlaneComboSelectionDataTemplate AcNamedUcsComboF9http://schemas.microsoft.com/winfx/2006/xaml/presentation8x,http://schemas.microsoft.com/winfx/2006/xaml@scm8clr-namespace:System.ComponentModel;assembly=WindowsBase1System&clr-namespace:System;assembly=mscorlib9adw1clr-namespace:Autodesk.Windows;assembly=AdWindowsCadiw:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindows-acr%clr-namespace:Autodesk.AutoCAD.RibbonKacmgdAclr-namespace:Autodesk.AutoCAD.ApplicationServices;assembly=acmgdCdata:clr-namespace:Autodesk.AutoCAD.Windows.Data;assembly=acmgdGdb@clr-namespace:Autodesk.AutoCAD.DatabaseServices;assembly=acdbmgdAcolors6clr-namespace:Autodesk.AutoCAD.Colors;assembly=acdbmgd.acw&clr-namespace:Autodesk.AutoCAD.WindowsResourceDictionary_1 ResourceDictionary_2$4./AcWindows;component/Ribbon/Controls/Base.xaml?ResourceDictionary_3$?9/AcWindows;component/Ribbon/Controls/ControlTooltips.xaml? %& & |& & z& & r& & & u& & p7 & k & & 7 7 & &  77 & 7770StaticResource_18$lockedObjectsChecker1& y77770StaticResource_19$lockedObjectsChecker1& 77770StaticResource_20$lockedObjectsChecker1& m77& =7& |!7777770StaticResource_21$lockedObjectsChecker1& $7777& l&& '7!7"7#& $+& %P,& &-7'7(& )v.7*7'7(& +/0StaticResource_12$nullToVariesConverter10StaticResource_11$lockedObjectsChecker1& ,T17-7&7)77'77+& .47/70& 1y57*7/70& 27737.7177/70StaticResource_14$ valueToNamedValueConverter10StaticResource_13$lockedObjectsChecker174& 5:7677787970StaticResource_16$ colorToNamedValueConverter10StaticResource_15$lockedObjectsChecker17:0StaticResource_7$"AcRibbonMenuItemSelectColors1& ;x=7<77787=7:0StaticResource_8$"AcRibbonMenuItemSelectColors1& >g?7?77787=7:0StaticResource_9$"AcRibbonMenuItemSelectColors1& @lA7A77787=7:0StaticResource_10$"AcRibbonMenuItemSelectColors1& BC7C70StaticResource_43$& plotStyleNameToDataItemConverter17D& EG7F77G& HI7I& JJ7K& LK& ML7N7O77P7Q7R7Q& SP7T7 7U7V7U7V7W& XX& YwY& Z[& [c[& \[& ]\& ^f\& _\& `]& an]& b]7c7[7d7Z& eG^7c7^7d7_& f^7c7\7d7]& gI_7c7`7d7a& h_7V7c7U7d0StaticResource_6$"booleanToVisibilityConverter1& it`& j`7i& k^a& la& ma& nb& oCb& pqb& qb0StaticResource_17$lockedObjectsChecker1& rd7s77#7X7k7b7X7l7e7X7m7h7g7X7n7f7X7o7t7X7p7t7j7q& uq7v7U& wr7v7V& xjr7y& zr7u& {=s& |s& })t& ~t& u& pu& u& Uv& v& >w7u& w7u& x7y7u0StaticResource_23$AcViewports_Single10StaticResource_24$AcViewports_TwoVertical10StaticResource_25$AcViewports_TwoHorizontal10StaticResource_26$AcViewports_ThreeRight10StaticResource_27$AcViewports_ThreeLeft10StaticResource_28$AcViewports_ThreeAbove10StaticResource_29$AcViewports_ThreeBelow10StaticResource_30$AcViewports_ThreeVertical10StaticResource_31$!AcViewports_ThreeHorizontal10StaticResource_32$AcViewports_FourEqual10StaticResource_33$AcViewports_FourRight10StaticResource_34$AcViewports_FourLeft1& Jy7w77& {7& |7$7& w}7%7& I~& ~& _& & & 3& ρ& j& & 77777777& 0StaticResource_41$AcMenuItemUCSUnnamed10StaticResource_42$AcMenuItemUCSWorld10StaticResource_35$AcMenuItemUCSTop10StaticResource_36$AcMenuItemUCSBottom10StaticResource_37$AcMenuItemUCSLeft10StaticResource_38$AcMenuItemUCSRight10StaticResource_39$AcMenuItemUCSFront10StaticResource_40$AcMenuItemUCSBack17& & -777CollectionViewSource_1#Z$Collections.TableStyles scm:SortDescription_1$ Name CollectionViewSource_3#Z$!Collections.DimensionStyles scm:SortDescription_3$ Name CollectionViewSource_4#Z$Collections.MleaderStyles scm:SortDescription_4$ Name CollectionViewSource_6#Z$Collections.TextStyles scm:SortDescription_5$ Name CollectionViewSource_5#Z$Collections.VisualStyles scm:SortDescription_6$ Name CollectionViewSource_8#Z$Collections.Linetypes scm:SortDescription_8$ SortOrderscm:SortDescription_9$ Name CollectionViewSource_9#Z$Collections.Lineweights scm:SortDescription_10$ SortOrderscm:SortDescription_11$ Name CollectionViewSource_12#Z$Collections.PlotStyles scm:SortDescription_18$ SortOrderscm:SortDescription_19$ Name CollectionViewSource_13#Z$Collections.LayerStates scm:SortDescription_20$ Name CollectionViewSource_14#Z$Collections.NamedViews scm:SortDescription_21$ Name CompositeCollection_1CollectionContainer_18Top$ Top$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_VIETOP$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_VIETOP . #Z$!Commands[^^C^^C_-VIEW _TOP] Bottom$ Bottom$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_VIEBOT$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_VIEBOT . #Z$$Commands[^^C^^C_-VIEW _BOTTOM]Left$ Left$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_VIELEF$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_VIELEF . #Z$"Commands[^^C^^C_-VIEW _LEFT] Right$ Right$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_VIERIG$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_VIERIG . #Z$#Commands[^^C^^C_-VIEW _RIGHT] Front$ Front$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_VIEFRO$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_VIEFRO . #Z$#Commands[^^C^^C_-VIEW _FRONT]Back$ Back$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_VIEBAC$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_VIEBAC . #Z$"Commands[^^C^^C_-VIEW _BACK] SW Isometric$ SW Isometric$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_VIESWI$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_VIESWI . #Z$#Commands[^^C^^C_-VIEW _SWISO] SE Isometric$ SE Isometric$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_VIESEI$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_VIESEI . #Z$#Commands[^^C^^C_-VIEW _SEISO] NE Isometric$ NE Isometric$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_VIENEI$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_VIENEI . #Z$#Commands[^^C^^C_-VIEW _NEISO] NW Isometric$ NW Isometric$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_VIENWI$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_VIENWI . #Z$#Commands[^^C^^C_-VIEW _NWISO]CollectionViewSource_16#Z$("RenderEngine.PredefinedOutputSizesCollectionViewSource_17#Z$$RenderEngine.CustomOutputSizesCompositeCollection_2CollectionContainer_38CollectionContainer_28CollectionViewSource_15#Z$Collections.Layers scm:SortDescription_22$ Name  Render Output Size Gallery$ Render Output Size Gallery8$ComboBox=$ RENDER8#Z$$RenderEngine.CurrentOutputSize$ TwoWay=DataTemplate_85.R StackPanel_28$ Horizontal=$16$ 300.+ TextBlock_24 Specify Image Size$Specify Image Size ... . #Z$RenderEngine.OutputSize  #Ribbon Combo Box - Table Styles$% Ribbon Combo Box - Table Styles8$ TABLESTYLE8DataTemplate_86.R TextBlock_25$ NamePriorityBinding_22.& Binding_57#Z$82Collections.Selection.CommonProperties[TableStyle]8 Binding_58#Z$$Collections.TableStyles.ActivePriorityBinding_4.& Binding_62#Z$71Collections.Selection.CommonProperties.TableStyle$ TwoWay= data:CompositeConverter_14. $ acr:DataItemToCommandConverter_2$"_optchprop _tablestyle {0} 2 Binding_7#Z$)#Collections.TableStyles.CurrentItem$ TwoWay= &"Ribbon Combo Box - Dimension Style$( "Ribbon Combo Box - Dimension Style8$DIMSTYLE8DataTemplate_70.R]$ mDockPanel DockPanel_8.$ Stretch=$ Name.+adw:ImageAligner_31$ Left=$ Center=$ Left=._$AnnotativeImage Image_118$ None=$y Collapsed=$ Left=8$ 0,0,2,0q$ mText TextBlock_11$ Center=$ Left=$CharacterEllipsis=$ Name !DataTrigger_32$ "True#* Annotative+.a Setter_453$$AnnotativeImage%y$ &Visible= PriorityBinding_6.& Binding_14#Z$<6Collections.Selection.CommonProperties[DimensionStyle]8 Binding_15#Z$("Collections.DimensionStyles.ActivePriorityBinding_7.& Binding_63#Z$;5Collections.Selection.CommonProperties.DimensionStyle$ TwoWay= data:CompositeConverter_15. $ acr:DataItemToCommandConverter_3$ _optchprop _dimstyle {0} 2 Binding_17#Z$-'Collections.DimensionStyles.CurrentItem$ TwoWay= ($Ribbon Combo Box - Multileader Style$* $Ribbon Combo Box - Multileader Style8$ MLEADERSTYLE8DataTemplate_72.R] DockPanel_9$ Name.+adiw:ImageAligner_3$ Left=$ Center=$ Left=._$AnnotativeImageAnnotativeImage$ None=$y Collapsed=$ Left=8$ 0,0,2,0q$ mText mText$ Center=$ Left=$CharacterEllipsis=$ Name !DataTrigger_33$ "True#* Annotative+.a Setter_454$$AnnotativeImage%y$ &Visible= PriorityBinding_8.& Binding_18#Z$:4Collections.Selection.CommonProperties[MLeaderStyle]8 Binding_19#Z$& Collections.MleaderStyles.ActivePriorityBinding_9.& Binding_64#Z$93Collections.Selection.CommonProperties.MLeaderStyle$ TwoWay= data:CompositeConverter_16. $ acr:DataItemToCommandConverter_4$_optchprop _mlstyle {0} 2 Binding_21#Z$+%Collections.MleaderStyles.CurrentItem$ TwoWay=DataTemplate_TextStyleItem.R StackPanel_30$ Top=$Vertical=$80$68.+ Image_139$48$ 1,0,1,0q8] DockPanel_11..+adiw:ImageAligner_8$ Left=$ Center=$ Left=._$"AnnotativeImageTextStyleItem Image_148$ None=$y Collapsed=8$ 0,0,2,0q$ TextStyleTextBlock TextBlock_27$16$ 'Center=$ Center=$ Center=$CharacterEllipsis=$ Wrap=$ Name !DataTrigger_43$ "True#* Annotative+.a Setter_478$"$AnnotativeImageTextStyleItem%y$ &Visible= Setter_477$$TextStyleTextBlock%$ &Left= *&DataTemplate_TextStyleSelectionBoxItem.R] DockPanel_12..+adiw:ImageAligner_10$ Left=$ Center=$ Left=._$+%AnnotativeImageSelectionTextStyleItem)%AnnotativeImageSelectionTextStyleItem$ None=$y Collapsed=8$ 0,0,2,0q$ SelectedTextStyleTextBlockSelectedTextStyleTextBlock$16$ Center=$CharacterEllipsis=$ Name !DataTrigger_44$ "True#* Annotative+.a Setter_479$+$%AnnotativeImageSelectionTextStyleItem%y$ &Visible=  Ribbon Gallery - Text Style$! Ribbon Gallery - Text Style8$ComboBox=(.$ )275Q88*$ STYLE8+$ Name,8-$ Name.$ NamePriorityBinding_10.& Binding_22#Z$93Collections.Selection.CommonProperties[TextStyleId]8 Binding_23#Z$#Collections.TextStyles.ActivePriorityBinding_11.& Binding_65#Z$82Collections.Selection.CommonProperties.TextStyleId$ TwoWay= data:CompositeConverter_17. $ acr:DataItemToCommandConverter_5$!_optchprop _textstyle {0} 2 Binding_25#Z$("Collections.TextStyles.CurrentItem$ TwoWay= adw:RibbonMenuItem_15$Manage Text Styles...$ Manage Text Styles... #Z$Commands[^^C^^C_STYLE]  #Ribbon Gallery - IPE Text Style$% Ribbon Gallery - IPE Text Style$ComboBox=(.$ )275Q88*$6 0res:///%prodname%btn.xmx/$10/$RCDATA_16_TXTSTYLE$6 0res:///%prodname%btn.xmx/$10/$RCDATA_32_TXTSTYLE$ STYLE8+$ Name,8-$ Name.$ Name#Z$TextEditor.TextStyle$ TwoWay= .*Ribbon Combo Box - Block Visibility States$0 *Ribbon Combo Box - Block Visibility States .$ BVSTATE#Z$ BlockEditor.VisibilitySets#Z$.(BlockEditor.IsVisibilityParameterPresent#Z$,&BlockEditor.CurrentVisibilityStateNameDataTemplate_73.R TextBlock_13 Render Presets Combo Box$ Render Presets Combo Box8$ComboBox=(.$ RENDERPRESETS#Z$Collections.RenderPresets+$ Name,$ Image-$ Name.$ Name#Z$*$RenderEngine.CurrentRenderPresetName8$ TwoWay=DataTemplate_98.R] DockPanel_14..+ TextBlock_38$ 200$ Name*DataTemplate_81.R] DockPanel_10.$16.+ TextBlock_21$CharacterEllipsis=$ Name$ AsterickTextBlock TextBlock_35$y Collapsed=$* !DataTrigger_45$ "True##Z$& RenderEngine.IsRenderPresetDirty8.a Setter_480$$AsterickTextBlock%y$ &Visible=  Manage Render Presets...$Manage Render Presets...$ Manage Render Presets... #Z$$Commands[^^C^^C_RENDERPRESETS] DataTemplate_Export.RStackPanel_Export$ Horizontal=.+TextBlock_Export $Export: TextBlock_Export1$ WordEllipsis=DataTemplate_PageSetup.RStackPanel_PageSetup$ Horizontal=.+TextBlock_PageSetup $ Page Setup: TextBlock_PageSetup1$ WordEllipsis=DataTemplate_74.R] StackPanel_3$ 0,0,0,1q.+ Border_7$1q._$ mImage Image_121$ None=$ObjectId8 TextBlock_14$ 2,0,0,0q$ Center=*Name+ !DataTrigger_41$ "True#$ IsByLayer.a Setter_474$ $mImage8&% DataTemplate_75.R] StackPanel_4.+ Border_8y$ Value8._$ mImage Image_122$ None=$ObjectId8 TextBlock_15$ 2,0,0,0q$CharacterEllipsis=$ Center=*Name+ !DataTrigger_42$ "True#$ IsByLayer.a Setter_475$ $mImage8&% acr:BindingBridge_2/PriorityBinding_13.& Binding_28#Z$71Collections.Selection.CommonProperties.LinetypeId$ TwoWay= data:CompositeConverter_10.2 $ acr:DataItemToCommandConverter_6$_chprop _ltype {0} 2 Binding_29#Z$'!Collections.Linetypes.CurrentItem$ TwoWay=  Ribbon Combo Box - Linetypes$" Ribbon Combo Box - Linetypes8(.$> 8res:///%prodname%btn.xmx/$10/$RCDATA_16_LINESTYLECONTROL$> 8res:///%prodname%btn.xmx/$10/$RCDATA_32_LINESTYLECONTROL88*$ 0157Q$LINETYPE8+$ Name,$ObjectId8-$ Name.$ NamePriorityBinding_12.& Binding_26#Z$60Collections.Selection.CommonProperties[LineType]8 Binding_27#Z$"Collections.Linetypes.Active Binding_698$ Target$ TwoWay=  Other...$Other...$ Other... #Z$Commands[^^C^^C_LINETYPE] DataTemplate_76.R StackPanel_5$ 0,0,0,1q$ Horizontal=$ Auto.+ Border_9$1q._$ mImage Image_123$ None=$ Value8 TextBlock_16$ 2,0,0,0q$ Center=*Name+ !DataTrigger_39$ "True#$ IsByLayer.a Setter_472$ $mImage8&% DataTemplate_77.R StackPanel_6$ 0,0,0,0q$ Horizontal=$ Auto.+ Border_10y$ Value8._$ mImage Image_124$ None=$ Value8 TextBlock_17$ 2,0,0,0q$ Center=*Name+ !DataTrigger_40$ "True#$ IsByLayer.a Setter_473$ $mImage8&%  !Ribbon Combo Box - Lineweight$# Ribbon Combo Box - Lineweight8(.$? 9res:///%prodname%btn.xmx/$10/$RCDATA_16_LINEWEIGHTCONTROL$? 9res:///%prodname%btn.xmx/$10/$RCDATA_32_LINEWEIGHTCONTROL88*$ 0157Q$ LWEIGHT8+$ Name,$ Value8-$ Name.$ NamePriorityBinding_14.& Binding_30#Z$82Collections.Selection.CommonProperties[Lineweight]8PriorityBinding_15.& Binding_31#Z$71Collections.Selection.CommonProperties.Lineweight$ TwoWay= data:CompositeConverter_11.2 $ acr:DataItemToCommandConverter_7$_chprop _lweight {0} 2 Binding_32#Z$& SystemVariables[CELWEIGHT].Value8$ TwoWay= Lineweight Settings...$Lineweight Settings...$ Lineweight Settings... #Z$Commands[^^C^^C_LWEIGHT]  Object Color Gallery$ Object Color Gallery8$ComboBox=(.$3 -res:///%prodname%btn.xmx/$10/$RCDATA_16_COLOR$3 -res:///%prodname%btn.xmx/$10/$RCDATA_32_COLOR88*$ COLOR8+$ Name-$ Name.$ NamePriorityBinding_16.& Binding_51#Z$3-Collections.Selection.CommonProperties[Color]8PriorityBinding_17.& Binding_34#Z$2,Collections.Selection.CommonProperties.Color$ TwoWay= data:CompositeConverter_12.2!acr:ColorToCommandConverter_12 Binding_35#Z$$SystemVariables[CECOLOR].Value8$ TwoWay= 2  $ Visual Styles Edge Color Gallery$& Visual Styles Edge Color Gallery8$ComboBox=(.$7 1res:///%prodname%btn.xmx/$10/$RCDATA_16_COLOREDGE$7 1res:///%prodname%btn.xmx/$10/$RCDATA_32_COLOREDGE88*$ VSEDGECOLOR8+$ Name-$ Name.$ Name Binding_36#Z$,&SystemVariables[VSEDGECOLOR].IsEnabled Binding_37#Z$("SystemVariables[VSEDGECOLOR].Value8$ TwoWay= 2  -)Visual Styles Obscured Edge Color Gallery$/ )Visual Styles Obscured Edge Color Gallery8$ComboBox=(.$3 -res:///%prodname%btn.xmx/$10/$RCDATA_16_COLOR$3 -res:///%prodname%btn.xmx/$10/$RCDATA_32_COLOR88*$VSOBSCUREDCOLOR8+$ Name-$ Name.$ Name Binding_38#Z$0*SystemVariables[VSOBSCUREDCOLOR].IsEnabled Binding_39#Z$,&SystemVariables[VSOBSCUREDCOLOR].Value8$ TwoWay= 2  1-Visual Styles Intersection Edge Color Gallery$3 -Visual Styles Intersection Edge Color Gallery8$ComboBox=(.$3 -res:///%prodname%btn.xmx/$10/$RCDATA_16_COLOR$3 -res:///%prodname%btn.xmx/$10/$RCDATA_32_COLOR88*$VSINTERSECTIONCOLOR8+$ Name-$ Name.$ Name Binding_40#Z$4.SystemVariables[VSINTERSECTIONCOLOR].IsEnabled Binding_41#Z$0*SystemVariables[VSINTERSECTIONCOLOR].Value8$ TwoWay= 2  Plot Style Gallery$ Plot Style Gallery8(.$7 1res:///%prodname%btn.xmx/$10/$RCDATA_16_PLOTSTYLE$7 1res:///%prodname%btn.xmx/$10/$RCDATA_32_PLOTSTYLE$ComboBox=$ PLOTSTYLE8+$ Name,$ Image-$ Name.$ NameDataTemplate_80.R TextBlock_20$ 200$ Name Binding_42#Z$#Collections.PlotStyles.ActivePriorityBinding_23.& Binding_70#Z$:4Collections.Selection.CommonProperties.PlotStyleName$ TwoWay=!data:MultiReplaceConverter_11.1data:ReplaceConverter_372Z3 data:NullToVariesConverter_142 Binding_71#Z$'!SystemVariables[CPLOTSTYLE].Value8$ TwoWay= adw:RibbonMenuItem_7$Other... #Z$ Commands[^^C^^C_PLOTSTYLE]  Layer State Gallery$ Layer State Gallery8(.$ComboBox=$ LAYER8-$ Name.$ NameDataTemplate_87.R StackPanel_29$ 0,0,0,1q$ Horizontal=$ 300.+ TextBlock_26$ Name Binding_44#Z$$Collections.LayerStates.Active Binding_45#Z$)#Collections.LayerStates.CurrentItem8$ TwoWay= adw:RibbonMenuItem_13$New Layer State...$LAYERSTATESAVE #Z$%Commands[^^C^^C_LAYERSTATESAVE]adw:RibbonMenuItem_14$Manage Layer States...$ LAYERSTATE #Z$!Commands[^^C^^C_LAYERSTATE] -)Ribbon Button - Render Output File Browse$/ )Ribbon Button - Render Output File Browse85.$> 8res:///%prodname%btn.xmx/$10/$RCDATA_16_FILEBROWSEDIALOG$ RENDER #Z$RenderEngine.OutputFile#Z$,&RenderEngine.IsRenderOutputFileEnabled($Ribbon Text Box - Render Output File$* $Ribbon Text Box - Render Output File8$ RENDER6#Z$'!RenderEngine.RenderOutputFileName#Z$,&RenderEngine.IsRenderOutputFileEnabledRibbonTextBoxItem$ RibbonTextBoxItem$ RIBBON Visual Styles Gallery$ Visual Styles Gallery8$ComboBox=$ Visual Styles(.8)$? 9res:///%prodname%btn.xmx/$10/$RCDATA_16_VISUALSTYLESSTYLE$? 9res:///%prodname%btn.xmx/$10/$RCDATA_32_VISUALSTYLESSTYLE$ VSCURRENT8+$ Name-$ Name.$ Name#Z$*$Collections.VisualStyles.CurrentItem8$ TwoWay=DataTemplate_96.R StackPanel_37$ Top=$Vertical=$80$68.+ Image_146$488 TextBlock_37$16$ 'Center=$ Center=$ Center=$CharacterEllipsis=$ Wrap=$ Name*DataTemplate_97.R] DockPanel_13..+ Image_147$ Left=$16$16y$ObjectId88 TextBlock_36$ 3,0,0,0q$CharacterEllipsis=$ Name adw:RibbonMenuItem_10$$Save as a New Visual Style ... .$ VSSAVE #Z$Commands[^^C^^C_VSSAVE]adw:RibbonMenuItem_12$Visual Styles Manager... .$ VISUALSTYLES #Z$#Commands[^^C^^C_VISUALSTYLES]  3D Navigation Combo Control$ Named Views$! 3D Navigation Combo Control8$ComboBox=$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_VIESWI$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_VIESWI(.$73$ -VIEW8+$ Name,$ Image-$ Name.$ NameDataTemplate_83.R StackPanel_26$ Horizontal=$ 300.+$ mImage mImage$16$16*Image+ TextBlock_22$ 2,0,0,0q$ Name !^MultiDataTrigger_1 8DataTrigger_349*ItemTemplateImageBinding+:Z Condition_18:9#Z$'!SystemVariables[PAPERSPACE].Value .0 Setter_457$ $mImage%$4&.res:///%prodname%btn.xmx/$10/$RCDATA_32_LAYTEM^MultiDataTrigger_2 8 Condition_29*ItemTemplateImageBinding+:Z Condition_38:9#Z$'!SystemVariables[PAPERSPACE].Value .0 Setter_458$ $mImage%$<&6res:///%prodname%btn.xmx/$10/$RCDATA_32_MODELSPACEVIEW *DataTemplate_95.R StackPanel_36$ Horizontal=$ 300.+$ mImage Image_133$16$16*Image+ TextBlock_34$ 2,0,0,0q$ Name !^MultiDataTrigger_3 8 Condition_49*Image+:Z Condition_58:9#Z$'!SystemVariables[PAPERSPACE].Value .0 Setter_459$ $mImage%$4&.res:///%prodname%btn.xmx/$10/$RCDATA_32_LAYTEM^MultiDataTrigger_4 8 Condition_69*Image+:Z Condition_78:9#Z$'!SystemVariables[PAPERSPACE].Value .0 Setter_460$ $mImage%$<&6res:///%prodname%btn.xmx/$10/$RCDATA_16_MODELSPACEVIEW  Binding_46#Z$("Collections.NamedViews.CurrentItem8$ TwoWay= adw:RibbonMenuItem_11$View Manager... .$ NEWVIEW #Z$Commands[^^C^^C_VIEW]  Style_3";. Setter_455% & Setter_456%&ControlTemplate_3"<.RContentPresenter_1 Style_2";. Setter_2%@OverridesDefaultStyle&. Setter_3%@J AllowDrop&. Setter_4%$&0 Setter_5%$&0 Setter_6%@FocusVisualStyle&Z Setter_7%&ControlTemplate_2"<.R$=PART_ContentHostPART_ContentHost|. $ Hidden=$ Hidden=. BitmapImage_2$<>6res:///%prodname%btn.xmx/$10/$RCDATA_16_RIBBON_LAYERON? BitmapImage_3$=>7res:///%prodname%btn.xmx/$10/$RCDATA_16_RIBBON_LAYEROFF? BitmapImage_4$>>8res:///%prodname%btn.xmx/$10/$RCDATA_16_RIBBON_LAYERLOCK? BitmapImage_5$@>:res:///%prodname%btn.xmx/$10/$RCDATA_16_RIBBON_LAYERUNLOCK? BitmapImage_6$@>:res:///%prodname%btn.xmx/$10/$RCDATA_16_RIBBON_LAYERFREEZE? BitmapImage_7$>>8res:///%prodname%btn.xmx/$10/$RCDATA_16_RIBBON_LAYERTHAW? BitmapImage_8$B>:res:///%prodname%btn.xmx/$10/$RCDATA_16_RIBBON_LAYERVPTHAW? data:MultiReplaceConverter_5.1data:ReplaceConverter_18828?data:ReplaceConverter_19828? data:MultiReplaceConverter_6.1data:ReplaceConverter_20828?data:ReplaceConverter_21828? data:MultiReplaceConverter_7.1data:ReplaceConverter_22828?data:ReplaceConverter_23828? data:MultiReplaceConverter_8.1data:ReplaceConverter_24828?data:ReplaceConverter_25828? data:CompositeConverter_9. data:MultiReplaceConverter_9.1data:ReplaceConverter_26828?data:ReplaceConverter_27828?2 data:CompositeConverter_13. data:SourceToTypeConverter_1"@"A&"acr:AcadColorToWPFColorConverter_1SolidColorBrush_1B#Z$60SystemVariables[VPOVERRIDEBACKGROUNDCOLOR].Value8System:String_1Turn a layer On or OffSystem:String_2#Freeze or thaw in ALL viewportsSystem:String_3&"Freeze or thaw in current viewportSystem:String_4Lock or Unlock a layerSystem:String_5Color of a layerSystem:String_6($Color of a layer in current viewportacr:BindingBridge_1/PriorityBinding_19.& Binding_47#Z$4.Collections.Selection.CommonProperties.LayerId$CPropertyChanged=$ TwoWay= data:CompositeConverter_1. $ acr:DataItemToCommandConverter_8$_chprop _layer {0} 2%!acr:FrozenOffLayerObjectChecker_1 Binding_52#Z$$Collections.Layers.CurrentItem$ TwoWay=$CPropertyChanged=acr:FrozenLayerChecker_1 Layer List Combo Box$ Layer List Combo Box8(.$ DName$ 0150Q$ LAYER8+$ Name,$ Image-$ Name.$ NameDataTemplate_82.R Border_13y$ IsVisible8{$ IsEnabled._ Grid_1 EColumnDefinition_1$ Auto$FIsOffColumnGroupColumnDefinition_2$ Auto$FIsFrozenColumnGroupColumnDefinition_3$ Auto$FIsVpFrozenColumnGroupColumnDefinition_4$ Auto$FIsLockedColumnGroupColumnDefinition_5$ Auto$FColorColumnGroupColumnDefinition_6$ Auto$F NameGroup .+dToggleButton_18$08GH$ IsOff$ TwoWay=.adiw:ImageAligner_4$ Center=$ Center=$ 0,0,3,0q._ Image_127$ IsOff8dToggleButton_28$18GH$IsFrozen$ TwoWay=.adiw:ImageAligner_5$ Center=$ Center=$ 0,0,3,0q._ Image_128$IsFrozen8dToggleButton_38 $28G H$IsFrozenInCurrentViewport$ TwoWay=y#Z$%SystemVariables[TILEMODE].Value8 .adiw:ImageAligner_6$ Center=$ Center=$ 0,0,3,0q._ Image_129$IsFrozenInCurrentViewport8 dToggleButton_48 $38GH$IsLocked$ TwoWay=.adiw:ImageAligner_7$ Center=$ Center=$ 0,0,3,0q._ Image_130$IsLocked8$I mLayerColor mLayerColor$18$188$4$ 0,0,3,0q$ yVisible=8G#Z$("Collections.Colors.Commands[Color]J$KTemplatedParent=$ Content.$L mColorBorder mColorBorder$1q._ Grid_2.+ Border_21$1q $1q._ Image_134$ Color8$ImOverridenColor Button_1$18$188$4$ 0,0,3,0q$y Collapsed=8G#Z$0*Collections.Colors.Commands[ColorOverride]J$KTemplatedParent=$ Content.$LmOverridenColorBordermOverridenColorBorder$1q._ Grid_3.+mOverridenColor$1q #FF393F48 #FF898D95$1q._ Border_20$1q$0q #FFF5F6F8._ Image_145$1q$ ColorOverride8$LmLayerNameBorder Border_18$5._ TextBox_1$5$ 340$CharacterEllipsis=$ M1500$ NameG$ Name !DataTrigger_35$ "True#$HasViewportOverrides.a Setter_465$$mLayerNameBorder8&%DataTrigger_36$ "True#$HasColorOverride.a Setter_468$$ mLayerColor%y$& Collapsed= Setter_469$$mOverridenColor%y$ &Visible=P Trigger_1$N mLayerColorO@J IsMouseOverP.. Setter_466$$ mColorBorder%& #FF0160BFP Trigger_2$NmOverridenColorO@J IsMouseOverP.. Setter_467$$mOverridenColorBorder%& #FF0160BFP Trigger_3O{P.. Setter_481%@JOpacity$&.5Q  Binding_688$ Target$ TwoWay= Binding_66#Z$%SystemVariables[TILEMODE].Value88Q Binding_67#Z$%SystemVariables[TILEMODE].Value88QAcViewports_Active8 .$" *Active Model Configuration*$"*Active Model Configuration*AcViewports_Single$ Single .8 #Z$ViewportsCommands[Single]AcViewports_TwoVertical$Two: Vertical . #Z$$ViewportsCommands[TwoVertical]AcViewports_TwoHorizontal$Two: Horizontal . #Z$& ViewportsCommands[TwoHorizontal]AcViewports_ThreeRight$ Three: Right . #Z$#ViewportsCommands[ThreeRight]AcViewports_ThreeLeft$ Three: Left . #Z$"ViewportsCommands[ThreeLeft]AcViewports_ThreeAbove$ Three: Above . #Z$#ViewportsCommands[ThreeAbove]AcViewports_ThreeBelow$ Three: Below . #Z$#ViewportsCommands[ThreeBelow]AcViewports_ThreeVertical$Three: Vertical . #Z$& ViewportsCommands[ThreeVertical]AcViewports_ThreeHorizontal$Three: Horizontal . #Z$("ViewportsCommands[ThreeHorizontal]AcViewports_FourEqual$ Four: Equal . #Z$"ViewportsCommands[FourEqual]AcViewports_FourRight$ Four: Right .8 #Z$"ViewportsCommands[FourRight]AcViewports_FourLeft$ Four: Left .8 #Z$!ViewportsCommands[FourLeft] Viewport Configurations List$" Viewport Configurations List8R.S.5.(.$ Set Viewports$: 4res:///%prodname%btn.xmx/$10/$RCDATA_16_MULTI_VPORTS$: 4res:///%prodname%btn.xmx/$10/$RCDATA_32_MULTI_VPORTS8$ VPORTS.T22222222 2 2 2 2 Create Viewports Drop-down$ Create Viewports Drop-downR.S.5.(.8$ VPORTS.TCreate Polygonal$ Create Polygonal$Create Polygonal$? 9res:///%prodname%btn.xmx/$10/$RCDATA_16_VIEW_VP_POLYGONAL$? 9res:///%prodname%btn.xmx/$10/$RCDATA_32_VIEW_VP_POLYGONAL8 #Z$!Commands[^^C^^C_-VPORTS _P]adw:RibbonCommandItem_1$ Create from Object$Create from Object$< 6res:///%prodname%btn.xmx/$10/$RCDATA_16_VIEW_VP_OBJECT$< 6res:///%prodname%btn.xmx/$10/$RCDATA_32_VIEW_VP_OBJECT8 #Z$!Commands[^^C^^C_-VPORTS _O] $ Annotation Text Height Combo Box$& Annotation Text Height Combo Box8U.$TEXTSIZE#Z$TextSize.TextHeight$ TwoWay=#Z$TextSize.FontSizes+ "Ribbon Combo Box - EplotExport$ What To Export Combo Box8*8$EXPORTEPLOTFORMAT#Z$EplotExport.ExportSet#Z$#EplotExport.CurrentItemExport$ TwoWay=+ adw:RibbonCombo_1$ Page Setup Combo Box8*8$EXPORTPAGESETUP#Z$EplotExport.PageSetupSet#Z$& EplotExport.CurrentItemPageSetup$ TwoWay=+CollectionViewSource_18#Z$Collections.UcsPlanes scm:SortDescription_23$ Name adw:RibbonMenuItem_16$ Top$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_VIETOP$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_VIETOP .adw:RibbonMenuItem_17$ Bottom$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_VIEBOT$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_VIEBOT .adw:RibbonMenuItem_18$ Left$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_VIELEF$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_VIELEF .adw:RibbonMenuItem_19$ Right$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_VIERIG$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_VIERIG .adw:RibbonMenuItem_20$ Front$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_VIEFRO$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_VIEFRO .adw:RibbonMenuItem_21$ Back$4 .res:///%prodname%btn.xmx/$10/$RCDATA_16_VIEBAC$4 .res:///%prodname%btn.xmx/$10/$RCDATA_32_VIEBAC . World$ World$2 ,res:///%prodname%btn.xmx/$10/$RCDATA_16_UCSW$2 ,res:///%prodname%btn.xmx/$10/$RCDATA_32_UCSW . Unnamed$ UnnamedV.$1 +res:///%prodname%btn.xmx/$10/$RCDATA_16_UCS$1 +res:///%prodname%btn.xmx/$10/$RCDATA_32_UCS .!data:MultiReplaceConverter_10.1data:ReplaceConverter_28#2ZW8?data:ReplaceConverter_29#2ZX8?data:ReplaceConverter_31#2ZY8?data:ReplaceConverter_32#2ZZ8?data:ReplaceConverter_33#2Z[8?data:ReplaceConverter_34#2Z\8?data:ReplaceConverter_35#2Z]8?data:ReplaceConverter_36#2Z^8?CompositeCollection_322 adw:RibbonSeparator_1222222 adw:RibbonSeparator_2CollectionContainer_48DataTemplate_99.R] DockPanel_15$ 0,0,0,0q.+ Border_22$0q._$ mImage Image_149$ None=$16$16$ Image TextBlock_39$ 2,0,0,0q$ Center=$ Name !DataTrigger_46#$ Image"Z.a Setter_482$ $mImage%y$& Collapsed=  Named UCS Combo Control$ Named UCS Combo Control8*$ UCS+$ Name,$ Image-$ Name.$ Name8#Z$'!Collections.UcsPlanes.CurrentItem8$ TwoWay=!: MSBAML```RNWindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35R8clr-namespace:System.ComponentModel;assembly=WindowsBaseSystem.ComponentModelOKmscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e0891&clr-namespace:System;assembly=mscorlibSystemD@AdWindows, Version=2.1.0.0, Culture=neutral, PublicKeyToken=nullF1clr-namespace:Autodesk.Windows;assembly=AdWindowsAutodesk.WindowsX:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindowsAutodesk.Internal.WindowsEAAcWindows, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nullA%clr-namespace:Autodesk.AutoCAD.RibbonAutodesk.AutoCAD.RibbonA=acmgd, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nulljAclr-namespace:Autodesk.AutoCAD.ApplicationServices;assembly=acmgd$Autodesk.AutoCAD.ApplicationServices\:clr-namespace:Autodesk.AutoCAD.Windows.Data;assembly=acmgdAutodesk.AutoCAD.Windows.DataC?acdbmgd, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nullf@clr-namespace:Autodesk.AutoCAD.DatabaseServices;assembly=acdbmgd!Autodesk.AutoCAD.DatabaseServicesR6clr-namespace:Autodesk.AutoCAD.Colors;assembly=acdbmgdAutodesk.AutoCAD.ColorsWSPresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35^ZWindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\XPresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35MergedDictionaries Source5/Autodesk.AutoCAD.Windows.Data.StandardConverter navStatusToBooleanConverter SourceType-'Autodesk.AutoCAD.Windows.Data.NavStatus TargetType#Autodesk.Windows.RibbonButton AcAnimationPlayCommandButton!Autodesk.Windows.RibbonItem Name Image93Autodesk.Private.Windows.RibbonImageSourceConverter LargeImage Tag("Autodesk.Windows.RibbonCommandItemCommandHandlerBinding60Autodesk.AutoCAD.ApplicationServices.Application  UIBindings Source Path IsEnabledBinding multiValueToBooleanConverter ` Converter`ConverterParameter ConverterConverterParameter "AcAnimationRecordCommandButton !AcAnimationPauseCommandButton AcAnimationSaveCommandButton $ AcAnimationSettingsCommandButton.(Autodesk.AutoCAD.Ribbon.OpenDrawingsList AcOpenDrawingsList Text TT_AcOpenDrawingsListToolTip SizeShowText Orientation5/Autodesk.AutoCAD.Ribbon.StatusBarPanesCheckList  AcStatusBarPanesCheckList TT_AcStatusBarPanesCheckList, &Autodesk.Windows.RibbonChecklistButton  AcRibbonLockingButton' !Autodesk.Windows.RibbonListButton IsSplit$ IsSynchronizedWithCurrentItem  TT_AcRibbonLockingButton  Items IsCheckableIsToolTipEnabledIsCheckedBinding  lockUIToBooleanConverter Mode3 -Autodesk.Internal.Windows.RibbonCompositeItem AcRibbonAutodeskSeekControl "TT_AcRibbonAutodeskSeekControlMinWidth Content Resources$ Autodesk.Windows.RibbonTextBox Key Prompt! ImageLocation" ShowImage# ShowImageAsButton$ InvokesCommand% AcceptTextOnLostFocus& CommandHandlerBinding RibbonContentSearchTextBox$ Autodesk.AutoCAD.Ribbon.Triple AcUi3DNavEyePoint' Point3d AcUi3DNavTargetPoint<6Autodesk.AutoCAD.Ribbon.Point3dDoubleToStringConverter "Point3dDoubleToStringConverter/)Autodesk.AutoCAD.Ribbon.RibbonHwndControl AcLayerFilterComboControl( ControlName )Module Ac3DNavPointTriplet1 TT_Ac3DNavPointTriplet1* Orientation,&Autodesk.Internal.Windows.ImageAligner Ac3DNavPointTriplet2 TT_Ac3DNavPointTriplet2"Autodesk.Windows.RibbonLabel AcBlockRibbonLabel+ TextBinding !AcBlockVisibilityStatesButton $ TT_AcBlockVisibilityStatesButton AcBlockVisibilityModeButton "TT_AcBlockVisibilityModeButton AcBlockVisibilityShowButton " TT_AcBlockVisibilityShowButton !AcBlockVisibilityHideButton ""TT_AcBlockVisibilityHideButton #AcExportWindowButton $TT_AcWindowButton %AcPageSetupButton &TT_AcPageSetupButton1+Autodesk.AutoCAD.Ribbon.RibbonCommandButton -')AcRibbonCommandButtonEnableGreaterThanOne (greaterThanOneConverter ))%AcRibbonCommandButtonEnableEqualToOne *equalToOneConverter %+!AcRibbonCommandButtonViewportJoin (,$TT_AcRibbonCommandButtonViewportJoin -shortToBooleanConverter !.AcRibbonCommandButtonQuickCUIF9http://schemas.microsoft.com/winfx/2006/xaml/presentation8x,http://schemas.microsoft.com/winfx/2006/xaml@scm8clr-namespace:System.ComponentModel;assembly=WindowsBase1System&clr-namespace:System;assembly=mscorlib9adw1clr-namespace:Autodesk.Windows;assembly=AdWindowsCadiw:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindows-acr%clr-namespace:Autodesk.AutoCAD.RibbonKacmgdAclr-namespace:Autodesk.AutoCAD.ApplicationServices;assembly=acmgdCdata:clr-namespace:Autodesk.AutoCAD.Windows.Data;assembly=acmgdGdb@clr-namespace:Autodesk.AutoCAD.DatabaseServices;assembly=acdbmgdAcolors6clr-namespace:Autodesk.AutoCAD.Colors;assembly=acdbmgdResourceDictionary_1 ResourceDictionary_2$4./AcWindows;component/Ribbon/Controls/Base.xaml?ResourceDictionary_3$?9/AcWindows;component/Ribbon/Controls/ControlToolTips.xaml? %F%& & ,77& 77&  77& 77& &  7& , 7 & Q 7 7 7 7 7 & 777& & & ,& Z& 7777777& 7777777& & Z7& 7& 7 & !87"& #7$& %+7&& '7(& )! 7*& + 7,77-7-& .M"77-7-data:StandardConverter_1""*&Ribbon Command Button - Animation Play$,&Ribbon Command Button - Animation Play$?9res:///%prodname%btn.xmx/$10/$RCDATA_16_WALK-THROUGH_PLAY$?9res:///%prodname%btn.xmx/$10/$RCDATA_32_WALK-THROUGH_PLAY$ ANIPATH# Z $5 /NativeFunctions[AcVmTools.arx|navPlayAnimation] `MultiBinding_38 $2.1 Binding_51# Z $ AnimationEditor.IsActive Binding_52# Z $ AnimationEditor.Status8$Paused,Recording,(Ribbon Command Button - Animation Record$.(Ribbon Command Button - Animation Record$A;res:///%prodname%btn.xmx/$10/$RCDATA_16_WALK-THROUGH_RECORD$A;res:///%prodname%btn.xmx/$10/$RCDATA_32_WALK-THROUGH_RECORD$ ANIPATH# Z $7 1NativeFunctions[AcVmTools.arx|navRecordAnimation] `MultiBinding_48 $2.1 Binding_53# Z $ AnimationEditor.IsActive Binding_54# Z $ AnimationEditor.Status8$Paused,Default+'Ribbon Command Button - Animation Pause$-'Ribbon Command Button - Animation Pause$@:res:///%prodname%btn.xmx/$10/$RCDATA_16_WALK-THROUGH_PAUSE$@:res:///%prodname%btn.xmx/$10/$RCDATA_32_WALK-THROUGH_PAUSE$ ANIPATH# Z $6 0NativeFunctions[AcVmTools.arx|navPauseRecording] `MultiBinding_58 $2.1 Binding_55# Z $ AnimationEditor.IsActive Binding_56# Z $ AnimationEditor.Status8$ Recording*&Ribbon Command Button - Animation Save$,&Ribbon Command Button - Animation Save$?9res:///%prodname%btn.xmx/$10/$RCDATA_16_WALK-THROUGH_SAVE$?9res:///%prodname%btn.xmx/$10/$RCDATA_32_WALK-THROUGH_SAVE$ ANIPATH# Z $5 /NativeFunctions[AcVmTools.arx|navSaveAnimation] `MultiBinding_68 $2.1 Binding_57# Z $ AnimationEditor.IsActive Binding_58# Z $ AnimationEditor.Status8$Paused,Recording.*Ribbon Command Button - Animation Settings$0*Ribbon Command Button - Animation Settings$;5res:///%prodname%btn.xmx/$10/$RCDATA_16_ANIM_SETTINGS$;5res:///%prodname%btn.xmx/$10/$RCDATA_32_ANIM_SETTINGS$ ANIPATH# Z $< 6NativeFunctions[AcVmTools.arx|navShowAnimationSetting]'#Ribbon Menu Button - Switch Windows$)#Ribbon Menu Button - Switch Windows$Switch Windows8$;5res:///%prodname%btn.xmx/$10/$RCDATA_16_OPEN_DRAWINGS$;5res:///%prodname%btn.xmx/$10/$RCDATA_32_OPEN_DRAWINGS$ Large=.$Vertical=$ OPEN+'Ribbon Menu Button - Status Bar Options$-'Ribbon Menu Button - Status Bar Options$ Status Bar8$>8res:///%prodname%btn.xmx/$10/$RCDATA_16_STATUS_BAR_PANES$>8res:///%prodname%btn.xmx/$10/$RCDATA_32_STATUS_BAR_PANES$ Large=.$Vertical=$ STATUSBAR adw:RibbonChecklistButton_2$.(Ribbon Checklist Button - Window Locking$ Horizontal=$Standard=.$93res:///%prodname%btn.xmx/$10/$RCDATA_16_RIBBON_LOCK$93res:///%prodname%btn.xmx/$10/$RCDATA_32_RIBBON_LOCK..8$ LOCKUI adw:RibbonCommandItem_1$Floating Toolbars/Panels..# Z $# SystemVariables[LOCKUI].Value8$4$ TwoWay=adw:RibbonCommandItem_2$Docked Toolbars/Panels..# Z $# SystemVariables[LOCKUI].Value8$1$ TwoWay=adw:RibbonCommandItem_3$Floating Windows..# Z $# SystemVariables[LOCKUI].Value8$8$ TwoWay=adw:RibbonCommandItem_4$Docked Windows..# Z $# SystemVariables[LOCKUI].Value8$2$ TwoWay=  RibbonAutodeskSeekControl$RibbonAutodeskSeekControl8$ 200Q$ SEEKFrameworkTemplate_1.R Grid_2  adw:RibbonTextBox_1RibbonContentSearchTextBox$ Seek design content$! InsideRight=".#.$.%.$93res:///%prodname%btn.xmx/$10/$RCDATA_16_SEEK_SEARCH8$ SEEK&# Z $ TextEditor.ContentSearch.+ContentControl_18|.  acr:Triple_1'# Z $$ CurrentViewport.CameraLocation$ TwoWay=  acr:Triple_2'# Z $ CurrentViewport.ViewCenter$ TwoWay=($acr:Point3dDoubleToStringConverter_1LayerFilterComboControl$(LayerFilterComboControl$LayerFilterComboControl$)AcDashboard.arx$ LAYER 3D Navigation PointTriplet1$!3D Navigation PointTriplet18$ CAMERADataTemplate_1.R StackPanel_1$* Horizontal=.+adiw:ImageAligner_1$ Left=$ Center=._ Image_119$16$ Uniform=$ 0,0,2,0q$D>res:///acdashboardres.dll/$10/$RCDATA_3DNAV_POINTTRIPLETPANEL1 TextBox_28 $ X8$ TwoWay= TextBox_38 $ Y8$ TwoWay= TextBox_48 $ Z8$ TwoWay= 3D Navigation PointTriplet2$!3D Navigation PointTriplet28$ CAMERADataTemplate_2.R StackPanel_2$* Horizontal=.+adiw:ImageAligner_2$ Left=$ Center=._ Image_120$16$ Uniform=$ 0,0,2,0q$D>res:///acdashboardres.dll/$10/$RCDATA_3DNAV_POINTTRIPLETPANEL2 TextBox_58 $ X8$ TwoWay= TextBox_68 $ Y8$ TwoWay= TextBox_78 $ Z8$ TwoWay=Ribbon Label - Block$Ribbon Label - Block$ BEDIT+# Z $ BlockEditor.BlockName3/Ribbon Command Button - Block Visibility States$5/Ribbon Command Button - Block Visibility States$F@res:///%prodname%btn.xmx/$10/$RCDATA_16_MANAGE_VISIBILITY_STATES$F@res:///%prodname%btn.xmx/$10/$RCDATA_32_MANAGE_VISIBILITY_STATES8$ BVSTATE # Z $. (BlockEditor.IsVisibilityParameterPresent# Z $ Commands[^^C^^C_BVSTATE ]1-Ribbon Command Button - Block Visibility Mode$3-Ribbon Command Button - Block Visibility Mode$=7res:///%prodname%btn.xmx/$10/$RCDATA_16_VISIBILITY_MODE$=7res:///%prodname%btn.xmx/$10/$RCDATA_32_VISIBILITY_MODE8$ BVMODE # Z $. (BlockEditor.IsVisibilityParameterPresent# Z $ Commands[$M=$(ifcomma;$(andcomma;$(>comma;$(getvarcomma;quote;bvmodequote;)comma;0))comma;^^C^^C_bvmode 0comma;^^C^^C_bvmode 1) ]1-Ribbon Command Button - Block Visibility Hide$3-Ribbon Command Button - Block Visibility Show$:4res:///%prodname%btn.xmx/$10/$RCDATA_16_MAKE_VISIBLE$:4res:///%prodname%btn.xmx/$10/$RCDATA_32_MAKE_VISIBLE8$ BVSHOW # Z $. (BlockEditor.IsVisibilityParameterPresent# Z $J DNativeFunctions[AcAuthEnviron.arx|executeBlockVisibilityShowCommand]2.Ribbon Command Button - Block Visibility State$3-Ribbon Command Button - Block Visibility Hide$<6res:///%prodname%btn.xmx/$10/$RCDATA_16_MAKE_INVISIBLE$<6res:///%prodname%btn.xmx/$10/$RCDATA_32_MAKE_INVISIBLE8$ BVHIDE # Z $. (BlockEditor.IsVisibilityParameterPresent# Z $J DNativeFunctions[AcAuthEnviron.arx|executeBlockVisibilityHideCommand]acr:RibbonCommandButton_48$ Export Window$Vertical=$Standard=.$93res:///%prodname%btn.xmx/$10/$RCDATA_PUBLISH_WINDOW$93res:///%prodname%btn.xmx/$10/$RCDATA_PUBLISH_WINDOW8$EXPORTSETTINGS# Z $3 -Commands[^^C^^C_exportsettings _WindowSelect] # Z $! EplotExport.EnableWindowBtnacr:RibbonCommandButton_49$ Page Setup$Vertical=$Standard=.$?9res:///%prodname%btn.xmx/$10/$RCDATA_16_PUBLISH_PAGESETUP$?9res:///%prodname%btn.xmx/$10/$RCDATA_32_PUBLISH_PAGESETUP8$EXPORTSETTINGS# Z $. (Commands[^^C^^C_exportsettings _PageSet] # Z $$ EplotExport.EnablePageSetupBtnacr:DisableOnSelect$%RibbonButton_EnableSelectionGT1.$ RIBBON # Z $! Collections.Selection.Count8)%Ribbon Button - Enable Selection == 1. # Z $! Collections.Selection.Count8RibbonButton-ViewportJoin$Join Viewports$:4res:///%prodname%btn.xmx/$10/$RCDATA_16_VIEW_VP_JOIN$:4res:///%prodname%btn.xmx/$10/$RCDATA_32_VIEW_VP_JOIN8$ -VPORTS# Z $" Commands[^^C^^C_-vports _j ] `MultiBinding_18 $2.1 Binding_49# Z $% SystemVariables[TILEMODE].Value8$1 Binding_50# Z $( "SystemVariables[BLOCKEDITOR].Value8$0adw:RibbonCommandItem_5.$QUICKCUI# Z $ Commands[^^C^^C_QUICKCUI] `MultiBinding_28 $2.1 Binding_1# Z $$ SystemVariables[ZERODOC].Value8$0 Binding_2# Z $( "SystemVariables[BLOCKEDITOR].Value8$0! MSBAML```RNWindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35R8clr-namespace:System.ComponentModel;assembly=WindowsBaseSystem.ComponentModelOKmscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e0891&clr-namespace:System;assembly=mscorlibSystemD@AdWindows, Version=2.1.0.0, Culture=neutral, PublicKeyToken=nullF1clr-namespace:Autodesk.Windows;assembly=AdWindowsAutodesk.WindowsX:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindowsAutodesk.Internal.WindowsEAAcWindows, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nullA%clr-namespace:Autodesk.AutoCAD.RibbonAutodesk.AutoCAD.RibbonA=acmgd, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nulljAclr-namespace:Autodesk.AutoCAD.ApplicationServices;assembly=acmgd$Autodesk.AutoCAD.ApplicationServices\:clr-namespace:Autodesk.AutoCAD.Windows.Data;assembly=acmgdAutodesk.AutoCAD.Windows.DataC?acdbmgd, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nullf@clr-namespace:Autodesk.AutoCAD.DatabaseServices;assembly=acdbmgd!Autodesk.AutoCAD.DatabaseServicesR6clr-namespace:Autodesk.AutoCAD.Colors;assembly=acdbmgdAutodesk.AutoCAD.ColorsWSPresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35^ZWindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\XPresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35MergedDictionaries Source,&Autodesk.Internal.Windows.RibbonSlider $ AcSectionPlaneTransparencySlider!Autodesk.Windows.RibbonItem Name TextMinimumMaximumTextBox1EditableTextBox1Visibility Tag TextBox1TextBinding60Autodesk.AutoCAD.ApplicationServices.Application  UIBindings Source Path Mode "int16ToAbsoluteDoubleConverter Converter ValueBinding)#Autodesk.Windows.RibbonToggleButton )%AcSectionPlaneLiveSectionToggleButton Image93Autodesk.Private.Windows.RibbonImageSourceConverter LargeImage("Autodesk.Windows.RibbonCommandItemIsCheckedBindingF9http://schemas.microsoft.com/winfx/2006/xaml/presentation8x,http://schemas.microsoft.com/winfx/2006/xaml@scm8clr-namespace:System.ComponentModel;assembly=WindowsBase1System&clr-namespace:System;assembly=mscorlib9adw1clr-namespace:Autodesk.Windows;assembly=AdWindowsCadiw:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindows-acr%clr-namespace:Autodesk.AutoCAD.RibbonKacmgdAclr-namespace:Autodesk.AutoCAD.ApplicationServices;assembly=acmgdCdata:clr-namespace:Autodesk.AutoCAD.Windows.Data;assembly=acmgdGdb@clr-namespace:Autodesk.AutoCAD.DatabaseServices;assembly=acdbmgdAcolors6clr-namespace:Autodesk.AutoCAD.Colors;assembly=acdbmgdResourceDictionary_1 ResourceDictionary_2$4./AcWindows;component/Ribbon/Controls/Base.xaml? %& 7& k"SectionPlaneTransparencySlider$ Transparency$0*Ribbon Slider - Section Plane Transparency$1Q$ 100Q.$ Visible=$ SECTIONPLANE # Z $B TT_AcSkyStatus1 ?TT_AcSkyStatus2 %@!AcVSMATERIALMODEDataBoundDropDown (A$TT_AcVSMATERIALMODEDataBoundDropDown BAcATTMODEDataBoundDropDown C TT_AcAttmode1 D TT_AcAttmode2 E TT_AcAttmode0 FAcUCSICONDataBoundDropDown 1G-ucsIconVariableToRibbonCommandButtonConverter H TT_AcUcsIcon3 I TT_AcUcsIcon1 J TT_AcUcsIcon0F9http://schemas.microsoft.com/winfx/2006/xaml/presentation8x,http://schemas.microsoft.com/winfx/2006/xaml@scm8clr-namespace:System.ComponentModel;assembly=WindowsBase1System&clr-namespace:System;assembly=mscorlib9adw1clr-namespace:Autodesk.Windows;assembly=AdWindowsCadiw:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindows-acr%clr-namespace:Autodesk.AutoCAD.RibbonKacmgdAclr-namespace:Autodesk.AutoCAD.ApplicationServices;assembly=acmgdCdata:clr-namespace:Autodesk.AutoCAD.Windows.Data;assembly=acmgdGdb@clr-namespace:Autodesk.AutoCAD.DatabaseServices;assembly=acdbmgdAcolors6clr-namespace:Autodesk.AutoCAD.Colors;assembly=acdbmgdResourceDictionary_1 ResourceDictionary_2$4./AcWindows;component/Ribbon/Controls/Base.xaml?ResourceDictionary_3$?9/AcWindows;component/Ribbon/Controls/ControlToolTips.xaml? %I& 777777777 & 777 77 77 & 7777777& b 77777777777& P777777777&  77777 77!77"& #l777$77%77&& '?"777(77)77*& +8&777,77-77.77/& 0+7771772773& 4.7775776777& 8x2777977:77;& <6777=77>77?& @:777A77A77A& B>777C77D77E& FuB7G77H77I77J!acr:RibbonDataBoundDropDown_2$%FRAME System Variable Drop-down.$ FRAME#Z$"SystemVariables[FRAME].Value8 $ TwoWay= #Z$& SystemVariables[FRAME].IsEnabled. acr:RibbonCommandButton_2$ AcFrame0$ Hide frames$ Horizontal=$Standard=.$71res:///%prodname%btn.xmx/$10/$RCDATA_16_FRAME_OFF$71res:///%prodname%btn.xmx/$10/$RCDATA_32_FRAME_OFF88acr:RibbonCommandButton_3$ AcFrame1$Display and plot frames$ Horizontal=$Standard=.$?9res:///%prodname%btn.xmx/$10/$RCDATA_16_FRAME_DISPLAYPLOT$?9res:///%prodname%btn.xmx/$10/$RCDATA_32_FRAME_DISPLAYPLOT88acr:RibbonCommandButton_4$ AcFrame2$#Display but don't plot frames$ Horizontal=$Standard=.$A;res:///%prodname%btn.xmx/$10/$RCDATA_16_FRAME_DISPLAYNOPLOT$A;res:///%prodname%btn.xmx/$10/$RCDATA_32_FRAME_DISPLAYNOPLOT88acr:RibbonCommandButton_5$ AcFrame3$ *Frames vary*$ Horizontal=$Standard=.$:4res:///%prodname%btn.xmx/$10/$RCDATA_16_FRAME_VARIES$:4res:///%prodname%btn.xmx/$10/$RCDATA_32_FRAME_VARIES.88!acr:RibbonDataBoundDropDown_3$& UOSNAP System Variable Drop-down.$ UOSNAP#Z$#SystemVariables[UOSNAP].Value8 $ TwoWay= #Z$'!SystemVariables[UOSNAP].IsEnabled. acr:RibbonCommandButton_6$ AcUOSNAP0$Snap to Underlays OFF$ Horizontal=$Standard=.$82res:///%prodname%btn.xmx/$10/$RCDATA_16_UOSNAP_OFF$82res:///%prodname%btn.xmx/$10/$RCDATA_32_UOSNAP_OFF88acr:RibbonCommandButton_7$ AcUOSNAP1$Snap to Underlays ON$ Horizontal=$Standard=.$71res:///%prodname%btn.xmx/$10/$RCDATA_16_UOSNAP_ON$71res:///%prodname%btn.xmx/$10/$RCDATA_32_UOSNAP_ON88acr:RibbonCommandButton_8$ AcUOSNAP2$*Underlay OSnap's vary*$ Horizontal=$Standard=.$;5res:///%prodname%btn.xmx/$10/$RCDATA_16_UOSNAP_VARIES$;5res:///%prodname%btn.xmx/$10/$RCDATA_32_UOSNAP_VARIES.88adw:RibbonSplitDropDown$1+EXPORTEPLOTFORMAT System Variable Drop-down..$ List=$ Large=.$Vertical=$EXPORTEPLOTFORMAT#Z$.(SystemVariables[EXPORTEPLOTFORMAT].Value8 $ TwoWay= #Z$2,SystemVariables[EXPORTEPLOTFORMAT].IsEnabled. acr:RibbonCommandButton_11$ AcEXPORTEPLOTFORMAT0$ Export$ DWFx$ Horizontal=$Standard=.$:4res:///%prodname%btn.xmx/$10/$RCDATA_16_PUBLISH_DWFX$:4res:///%prodname%btn.xmx/$10/$RCDATA_32_PUBLISH_DWFX8.8#Z$!Commands[^^C^^C_EXPORTDWFX]acr:RibbonCommandButton_10$ AcEXPORTEPLOTFORMAT1$ Export$ DWF$ Horizontal=$Standard=.$93res:///%prodname%btn.xmx/$10/$RCDATA_16_PUBLISH_DWF$93res:///%prodname%btn.xmx/$10/$RCDATA_32_PUBLISH_DWF8.8#Z$ Commands[^^C^^C_EXPORTDWF]acr:RibbonCommandButton_9$ AcEXPORTEPLOTFORMAT2$ Export$ PDF$ Horizontal=$Standard=.$93res:///%prodname%btn.xmx/$10/$RCDATA_16_PUBLISH_PDF$93res:///%prodname%btn.xmx/$10/$RCDATA_32_PUBLISH_PDF8.8#Z$ Commands[^^C^^C_EXPORTPDF]!acr:RibbonDataBoundDropDown_5$3-SUBOBJSELECTIONMODE System Variable Drop-down.$SUBOBJSELECTIONMODE#Z$5/SystemVariables[SUBOBJSELECTIONMODE].MutedValue8 $ TwoWay= #Z$4.SystemVariables[SUBOBJSELECTIONMODE].IsEnabled. acr:RibbonCommandButton_12$ AcSubObjSelect0$ No Filter$ Horizontal=$Standard=.$;5res:///%prodname%btn.xmx/$10/$RCDATA_16_SUBOBJECT_ALL$;5res:///%prodname%btn.xmx/$10/$RCDATA_32_SUBOBJECT_ALL88acr:RibbonCommandButton_13$ AcSubObjSelect1$ Vertex$ Horizontal=$Standard=.$>8res:///%prodname%btn.xmx/$10/$RCDATA_16_SUBOBJECT_Vertex$>8res:///%prodname%btn.xmx/$10/$RCDATA_32_SUBOBJECT_Vertex88acr:RibbonCommandButton_14$ AcSubObjSelect2$ Edge$ Horizontal=$Standard=.$<6res:///%prodname%btn.xmx/$10/$RCDATA_16_SUBOBJECT_Edge$<6res:///%prodname%btn.xmx/$10/$RCDATA_32_SUBOBJECT_Edge88acr:RibbonCommandButton_15$ AcSubObjSelect3$ Face$ Horizontal=$Standard=.$<6res:///%prodname%btn.xmx/$10/$RCDATA_16_SUBOBJECT_Face$<6res:///%prodname%btn.xmx/$10/$RCDATA_32_SUBOBJECT_Face88acr:RibbonCommandButton_16$ AcSubObjSelect4$ Solid History$ Horizontal=$Standard=.$D>res:///%prodname%btn.xmx/$10/$RCDATA_16_SUBOBJECT_SolidHistory$D>res:///%prodname%btn.xmx/$10/$RCDATA_32_SUBOBJECT_SolidHistory8 8 !acr:RibbonDataBoundDropDown_6$,&DEFAULTGIZMO System Variable Drop-down.$ DEFAULTGIZMO#Z$.(SystemVariables[DEFAULTGIZMO].MutedValue8 $ TwoWay= #Z$-'SystemVariables[DEFAULTGIZMO].IsEnabled. acr:RibbonCommandButton_17$ AcSubObjSelect0$ Move Gizmo$ Horizontal=$Standard=.$82res:///%prodname%btn.xmx/$10/$RCDATA_16_GIZMO_MOVE$82res:///%prodname%btn.xmx/$10/$RCDATA_32_GIZMO_MOVE88acr:RibbonCommandButton_18$ AcSubObjSelect1$ Rotate Gizmo$ Horizontal=$Standard=.$:4res:///%prodname%btn.xmx/$10/$RCDATA_16_GIZMO_ROTATE$:4res:///%prodname%btn.xmx/$10/$RCDATA_32_GIZMO_ROTATE88acr:RibbonCommandButton_19$ AcSubObjSelect2$ Scale Gizmo$ Horizontal=$Standard=.$93res:///%prodname%btn.xmx/$10/$RCDATA_16_GIZMO_SCALE$93res:///%prodname%btn.xmx/$10/$RCDATA_32_GIZMO_SCALE88acr:RibbonCommandButton_52$ AcSubObjSelect3$No Gizmo$ Horizontal=$Standard=.$60res:///%prodname%btn.xmx/$10/$RCDATA_16_GIZMO_NO$60res:///%prodname%btn.xmx/$10/$RCDATA_32_GIZMO_NO88"acr:RibbonDataBoundDropDown_16$1+SMOOTHMESHCONVERT System Variable Drop-down.$SMOOTHMESHCONVERT#Z$.(SystemVariables[SMOOTHMESHCONVERT].Value8 $ TwoWay= #Z$2,SystemVariables[SMOOTHMESHCONVERT].IsEnabled. acr:RibbonCommandButton_48$ AcSmoothMeshConvert0$Smooth, optimized$ Horizontal=$Standard=.$/)Creates a smooth model that merges faces.$>8res:///%prodname%btn.xmx/$10/$RCDATA_16_OM_SMOOTH_MERGED$>8res:///%prodname%btn.xmx/$10/$RCDATA_32_OM_SMOOTH_MERGED88acr:RibbonCommandButton_49$ AcSmoothMeshConvert1$Smooth, not optimized$ Horizontal=$Standard=.$WQCreates a smooth model with the same number of faces as the original mesh object.$B8res:///%prodname%btn.xmx/$10/$RCDATA_16_RETAIN_ATTRIBUTE$>8res:///%prodname%btn.xmx/$10/$RCDATA_32_RETAIN_ATTRIBUTE88acr:RibbonCommandButton_46$ AcAttmode2$ Display All$ Horizontal=$Standard=.$?9res:///%prodname%btn.xmx/$10/$RCDATA_16_DISPLAY_ATTRIBUTE$?9res:///%prodname%btn.xmx/$10/$RCDATA_32_DISPLAY_ATTRIBUTE88acr:RibbonCommandButton_47$ AcAttmode0$Hide All$ Horizontal=$Standard=.$<6res:///%prodname%btn.xmx/$10/$RCDATA_16_HIDE_ATTRIBUTE$<6res:///%prodname%btn.xmx/$10/$RCDATA_32_HIDE_ATTRIBUTE88"acr:RibbonDataBoundDropDown_17$'!UCSICON System Variable Drop-down.$ UCSICON#Z$$SystemVariables[UCSICON].Value8 $ TwoWay= #Z$("SystemVariables[UCSICON].IsEnabled. acr:RibbonCommandButton_54$ AcUcsIcon3$Show UCS Icon at Origin$ Horizontal=$Standard=.$B%TT_AcTableCellUpdateLinkCommandButtonB& ?& @7A7?& Bk7C& D7E& F7G& HW7I& J7"7"7"7"7"7"7"7"7"7"& K *7#77#77#77#7& L/7$7 & Mq07$7 & N17$7 & O>37$7 & P47$7& Q67$7& R77$7& S87$7& Td:7$7& U;7 7L7 7M7 7N7 7O77P77Q77R77S77T& V=7U0StaticResource_8$"AcTableAlignmentMenu_TopLeft10StaticResource_9$$AcTableAlignmentMenu_TopCenter10StaticResource_10$#AcTableAlignmentMenu_TopRight10StaticResource_11$%AcTableAlignmentMenu_MiddleLeft10StaticResource_12$'!AcTableAlignmentMenu_MiddleCenter10StaticResource_13$& AcTableAlignmentMenu_MiddleRight10StaticResource_14$%AcTableAlignmentMenu_BottomLeft10StaticResource_15$'!AcTableAlignmentMenu_BottomCenter10StaticResource_16$& AcTableAlignmentMenu_BottomRight1& W8?& XC7Y7Z7[7\7]0StaticResource_7$"AcRibbonMenuItemSelectColors1db:DataTypeParameter_1$ Double=$ Angle=db:DataTypeParameter_2$ Double=$Currency=db:DataTypeParameter_3$ Date=$Unitless=db:DataTypeParameter_4$ Double=$Unitless=db:DataTypeParameter_5$ General=$Unitless=db:DataTypeParameter_6$ Double=$ Percentage=db:DataTypeParameter_7$ Point3d=$Unitless=db:DataTypeParameter_8$ String=$Unitless=db:DataTypeParameter_9$ Long=$Unitless=db:DataTypeParameter_10$ Unknown=$Unitless=db:CellAlignment_1 TopLeft=db:CellAlignment_2 TopCenter=db:CellAlignment_3 TopRight=db:CellAlignment_4 MiddleLeft=db:CellAlignment_5 MiddleCenter=db:CellAlignment_6 MiddleRight=db:CellAlignment_7 BottomLeft=db:CellAlignment_8 BottomCenter=db:CellAlignment_9 BottomRight=acr:CellLockedStyle_1 Unlocked=acr:CellLockedStyle_2 ContentLocked=acr:CellLockedStyle_3 FormatLocked=acr:CellLockedStyle_4ContentAndFormatLocked= data:MultiReplaceConverter_4.data:ReplaceConverter_888data:ReplaceConverter_988data:ReplaceConverter_1088data:ReplaceConverter_1188data:ReplaceConverter_1288 data:ReplaceConverter_138 8 data:ReplaceConverter_148 8 data:ReplaceConverter_1588data:ReplaceConverter_1688data:ReplaceConverter_1788data:CompositeConverter_7.22data:CompositeConverter_8.-)acr:CellStateToCellLockedStyleConverter_1data:StandardConverter_4" " data:StandardConverter_5" " adw:RibbonGallery_1$ Cell Styles Gallery8 $ ComboBox=.$ 200Q$ EDITTABLECELL$ Name#Z$!Collections.TableCellStyles#Z$?9Collections.Selection.CommonProperties.SubSelection.Style8$ TwoWay=`MultiBinding_18$2.1 Binding_49#Z$("Collections.TableCellStyles.Active Binding_50#Z$JDCollections.Selection.CommonProperties.SubSelection.IsFormatEditableDataTemplate_80.R TextBlock_20$ 200$ Name  Create new cell style...$Create new cell style...$ Create new cell style.... #Z$C=Commands[^^R^^C^^C_EDITTABLECELL _Style _Newtablestyle _Quit] Manage cell styles...$Manage cell styles...$ Manage cell styles.... #Z$D>Commands[^^R^^C^^C_EDITTABLECELL _Style _Edittablestyle _Quit] &"acr:CellRangeToCanMergeConverter_1adw:RibbonSplitButton_3$ EDITTABLECELL#Z$93Collections.Selection.CommonProperties.SubSelection8($acr:CellRangeToCanUnmergeConverter_1acr:RibbonCommandButton_57$;!5res:///%prodname%btn.xmx/$10/$RCDATA_16_UNMERGE_CELLS$;"5res:///%prodname%btn.xmx/$10/$RCDATA_32_UNMERGE_CELLS8 $ EDITTABLECELL#Z$93Collections.Selection.CommonProperties.SubSelection8 #Z$.(Commands[^^C^^C_EditTableCell _O _U _Q ]acr:RibbonCommandButton_58$:!4res:///%prodname%btn.xmx/$10/$RCDATA_16_INSERT_ABOVE$:"4res:///%prodname%btn.xmx/$10/$RCDATA_32_INSERT_ABOVE8 $ EDITTABLECELL#Z$NHCollections.Selection.CommonProperties.SubSelection.TopLeft.CanInsertRow #Z$/)Commands[^^C^^C_EditTableCell _O _AB _Q ]acr:RibbonCommandButton_59$:!4res:///%prodname%btn.xmx/$10/$RCDATA_16_INSERT_BELOW$:"4res:///%prodname%btn.xmx/$10/$RCDATA_32_INSERT_BELOW8 $ EDITTABLECELL#Z$YSCollections.Selection.CommonProperties.SubSelection.BottomRightPlusOne.CanInsertRow #Z$/)Commands[^^C^^C_EditTableCell _O _BE _Q ]acr:RibbonCommandButton_60$8!2res:///%prodname%btn.xmx/$10/$RCDATA_16_DELETE_ROW$8"2res:///%prodname%btn.xmx/$10/$RCDATA_32_DELETE_ROW8 $ EDITTABLECELL#Z$GACollections.Selection.CommonProperties.SubSelection.CanDeleteRows #Z$/)Commands[^^C^^C_EditTableCell _O _RO _Q ]acr:RibbonCommandButton_61$9!3res:///%prodname%btn.xmx/$10/$RCDATA_16_INSERT_LEFT$9"3res:///%prodname%btn.xmx/$10/$RCDATA_32_INSERT_LEFT8 $ EDITTABLECELL#Z$QKCollections.Selection.CommonProperties.SubSelection.TopLeft.CanInsertColumn #Z$/)Commands[^^C^^C_EditTableCell _O _LE _Q ]acr:RibbonCommandButton_62$A!;res:///%prodname%btn.xmx/$10/$RCDATA_16_INSERT_COLUMN_RIGHT$A";res:///%prodname%btn.xmx/$10/$RCDATA_32_INSERT_COLUMN_RIGHT8 $ EDITTABLECELL#Z$\VCollections.Selection.CommonProperties.SubSelection.BottomRightPlusOne.CanInsertColumn #Z$/)Commands[^^C^^C_EditTableCell _O _RI _Q ]acr:RibbonCommandButton_63$;!5res:///%prodname%btn.xmx/$10/$RCDATA_16_DELETE_COLUMN$;"5res:///%prodname%btn.xmx/$10/$RCDATA_32_DELETE_COLUMN8 $ EDITTABLECELL#Z$JDCollections.Selection.CommonProperties.SubSelection.CanDeleteColumns #Z$/)Commands[^^C^^C_EditTableCell _O _CO _Q ])%acr:CellRangeToCanDataLinkConverter_1acr:RibbonCommandButton_64$6!0res:///%prodname%btn.xmx/$10/$RCDATA_16_LINKCELL$6"0res:///%prodname%btn.xmx/$10/$RCDATA_32_LINKCELL8 $DATALINK#Z$93Collections.Selection.CommonProperties.SubSelection8 #Z$.(Commands[^^C^^C_EditTableCell _D _N _Q ]acr:RibbonCommandButton_65$9!3res:///%prodname%btn.xmx/$10/$RCDATA_16_UPDATE_DATA$9"3res:///%prodname%btn.xmx/$10/$RCDATA_32_UPDATE_DATA8 $DATALINKUPDATE#Z$BCommands[^^C^^C_EditTableCell _Content _Datatype _Angle _Quit] adw:RibbonMenuItem_100$Currency$)1.*#Z$BCommands[^^C^^C_EditTableCell _Content _Datatype _Point _Quit] adw:RibbonMenuItem_106$ Text$)7.*#Z$B!8res:///%prodname%btn.xmx/$10/$RCDATA_16_TBL_MIDDLE_RIGHT$>"8res:///%prodname%btn.xmx/$10/$RCDATA_32_TBL_MIDDLE_RIGHT*#Z$C=Collections.Selection.CommonProperties.SubSelection.Alignment88+$ OneWay= #Z$A;Commands[^^C^^C_EditTableCell _Format _ALignment _MR _Quit] adw:RibbonMenuItem_119$ Bottom Left$=!7res:///%prodname%btn.xmx/$10/$RCDATA_16_TBL_BOTTOM_LEFT$="7res:///%prodname%btn.xmx/$10/$RCDATA_32_TBL_BOTTOM_LEFT*#Z$C=Collections.Selection.CommonProperties.SubSelection.Alignment88+$ OneWay= #Z$A;Commands[^^C^^C_EditTableCell _Format _ALignment _BL _Quit] adw:RibbonMenuItem_120$ Bottom Center$?!9res:///%prodname%btn.xmx/$10/$RCDATA_16_TBL_BOTTOM_CENTER$?"9res:///%prodname%btn.xmx/$10/$RCDATA_32_TBL_BOTTOM_CENTER*#Z$C=Collections.Selection.CommonProperties.SubSelection.Alignment88+$ OneWay= #Z$A;Commands[^^C^^C_EditTableCell _Format _ALignment _BC _Quit] adw:RibbonMenuItem_121$ Bottom Right$>!8res:///%prodname%btn.xmx/$10/$RCDATA_16_TBL_BOTTOM_RIGHT$>"8res:///%prodname%btn.xmx/$10/$RCDATA_32_TBL_BOTTOM_RIGHT*#Z$C=Collections.Selection.CommonProperties.SubSelection.Alignment88+$ OneWay= #Z$A;Commands[^^C^^C_EditTableCell _Format _ALignment _BR _Quit] data:MultiReplaceConverter_5.data:ReplaceConverter_1888data:ReplaceConverter_1988data:ReplaceConverter_2088data:ReplaceConverter_2188data:ReplaceConverter_2288 data:ReplaceConverter_238 8 data:ReplaceConverter_248 8 data:ReplaceConverter_2588data:ReplaceConverter_2688adw:RibbonMenuButton_9$ Alignment$#Vertical=$ $Large=%.&.'.$ EDITTABLECELL$4!.res:///%prodname%btn.xmx/$10/$RCDATA_16_TABSUR$4".res:///%prodname%btn.xmx/$10/$RCDATA_32_TABSUR#Z$JDCollections.Selection.CommonProperties.SubSelection.IsFormatEditable,#Z$C=Collections.Selection.CommonProperties.SubSelection.Alignment8 (222222222 adw:RibbonMenuButton_10$ Formula$#Vertical=$ $Large=%.&.$;!5res:///%prodname%btn.xmx/$10/$RCDATA_16_INSERTFORMULA$;"5res:///%prodname%btn.xmx/$10/$RCDATA_32_INSERTFORMULA'.$ EDITTABLECELL#Z$KECollections.Selection.CommonProperties.SubSelection.IsContentEditable ( adw:RibbonMenuItem_122$ Sum. #Z$RLCommands[^^R_EditTableCell _ExecuteOneAction _Operation _insertFOrmula _Sum] adw:RibbonMenuItem_123$ Average. #Z$VPCommands[^^R_EditTableCell _ExecuteOneAction _Operation _insertFOrmula _Average] adw:RibbonMenuItem_124$ Count. #Z$TNCommands[^^R_EditTableCell _ExecuteOneAction _Operation _insertFOrmula _COunt] adw:RibbonMenuItem_125$ Cell. #Z$SMCommands[^^R_EditTableCell _ExecuteOneAction _Operation _insertFOrmula _CEll] adw:RibbonMenuItem_126$Equation. #Z$WQCommands[^^R_EditTableCell _ExecuteOneAction _Operation _insertFOrmula _Equation] Background Color Gallery$ Background Color Gallery8 $ ComboBox=.$3!-res:///%prodname%btn.xmx/$10/$RCDATA_16_COLOR$3"-res:///%prodname%btn.xmx/$10/$RCDATA_32_COLOR88-$ EDITTABLECELL8$ Name.$ Name/$ Name#Z$JDCollections.Selection.CommonProperties.SubSelection.IsFormatEditable#Z$ICCollections.Selection.CommonProperties.SubSelection.BackgroundColor8$ TwoWay= 2 !it MSBAML```RNWindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35R8clr-namespace:System.ComponentModel;assembly=WindowsBaseSystem.ComponentModelOKmscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e0891&clr-namespace:System;assembly=mscorlibSystemD@AdWindows, Version=2.1.0.0, Culture=neutral, PublicKeyToken=nullF1clr-namespace:Autodesk.Windows;assembly=AdWindowsAutodesk.WindowsX:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindowsAutodesk.Internal.WindowsEAAcWindows, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nullA%clr-namespace:Autodesk.AutoCAD.RibbonAutodesk.AutoCAD.RibbonA=acmgd, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nulljAclr-namespace:Autodesk.AutoCAD.ApplicationServices;assembly=acmgd$Autodesk.AutoCAD.ApplicationServices\:clr-namespace:Autodesk.AutoCAD.Windows.Data;assembly=acmgdAutodesk.AutoCAD.Windows.DataC?acdbmgd, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nullf@clr-namespace:Autodesk.AutoCAD.DatabaseServices;assembly=acdbmgd!Autodesk.AutoCAD.DatabaseServicesR6clr-namespace:Autodesk.AutoCAD.Colors;assembly=acdbmgdAutodesk.AutoCAD.ColorsWSPresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35^ZWindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\XPresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35MergedDictionaries Source.(Autodesk.AutoCAD.Ribbon.AcFocusConverter focusConverter5/Autodesk.AutoCAD.Windows.Data.StandardConverter ($paragraphAlignmentToBooleanConverter SourceType=7Autodesk.AutoCAD.Windows.Data.IPEParagraphAlignmentType TargetType columnTypeToBooleanConverter1+Autodesk.AutoCAD.Windows.Data.IPEColumnType '#dynamicColumnTypeToBooleanConverter82Autodesk.AutoCAD.Windows.Data.IPEDynamicColumnType &"staticColumnTypeToBooleanConverter71Autodesk.AutoCAD.Windows.Data.IPEStaticColumnType93Autodesk.AutoCAD.Windows.Data.Int32ToImageConverter columnTypeToImageConverter Images UriSource #columnTypeToLargeImageConverter %!attachmentPointToBooleanConverter60Autodesk.AutoCAD.Windows.Data.IPEAttachmentPoint '#linespacingFactorToBooleanConverter # numberingTypeToBooleanConverter4.Autodesk.AutoCAD.Windows.Data.IPENumberingType' !Autodesk.Windows.RibbonMenuButton  AcIPEJustificationMenu! Autodesk.Windows.RibbonItem  Text# Autodesk.Windows.RibbonButton Orientation  Size ShowText Image9 3Autodesk.Private.Windows.RibbonImageSourceConverter LargeImage' !Autodesk.Windows.RibbonListButton IsSplit$ IsSynchronizedWithCurrentItem  Tag  Items%Autodesk.Windows.RibbonMenuItem("Autodesk.Windows.RibbonCommandItemCommandParameterIsCheckedBinding60Autodesk.AutoCAD.ApplicationServices.Application UIBindings Source Path ConverterConverterParameter ModeCommandHandlerBinding  AcIPELineSpacingMenu IsEnabledBinding& Autodesk.Windows.RibbonSeparator  AcIPENumberingMenu enumSubsetToBooleanConverter Items AcIPESymbolMenu AcIPEFindReplaceMenuButton AcIPEUndoButton AcIPERedoButton AcIPECloseButton AcIPEFieldButton AcIPEParagraphButton  Name AcIPEMakeUpperCase AcIPEMakeLowerCase AcIPESpellDictionaries AcIPEImportText ShowImage)#Autodesk.Windows.RibbonToggleButton  AcIPEAutoCaps AcIPECombineParagraphs AcIPEBackgroundMask AcIPESpellCheckSettings AcIPEColumnsMenu ImageBinding LargeImageBinding AcIPEOptionsMenu4.Autodesk.AutoCAD.Ribbon.RibbonFormattedSpinner AcIPEObliqueAngleSpinner$Autodesk.Windows.RibbonSpinnerMinimum Maximum! IsEditable "Change# ValueBinding  AcIPETrackingSpinner !AcIPEWidthFactorSpinner3-Autodesk.Internal.Windows.RibbonCompositeItem "AcRibbonFindTextControl #TT_AcRibbonFindTextControl$ ToolTip% MinWidth&Content' Resources$Autodesk.Windows.RibbonTextBox $Key (Prompt) ImageLocation*ShowImageAsButton+InvokesCommand,AcceptTextOnLostFocus-CommandHandlerBinding %AcRibbonFindTextBox-'Autodesk.Windows.RibbonRadioButtonGroup #&AcParagraphAlignIPEGroupButtons . Id / KeyTip"Autodesk.Windows.RibbonCombo 'AcIPEFontSizeCombo0 IsEditable1TextPath 2 Width!Autodesk.Windows.RibbonList3CurrentBinding4ItemsSourceBinding (nullToBooleanConverter5EditableTextBinding6ItemTemplateTextBinding )AcIPEFontNameCombo * mFontName7ItemTemplateImageBinding$Autodesk.Windows.RibbonGallery +AcIPEFontColorCombo8 DisplayMode ",AcGalleryColorItemDataTemplate9 ItemTemplate .-*AcGalleryColorSelectionBoxItemDataTemplate:SelectionBoxItemTemplate . objectColors!;ItemTemplateToolTipBinding<ItemTemplateIdBinding /colorToNamedValueConverter= MenuItems> ResourceKeyF9http://schemas.microsoft.com/winfx/2006/xaml/presentation8x,http://schemas.microsoft.com/winfx/2006/xaml@scm8clr-namespace:System.ComponentModel;assembly=WindowsBase1System&clr-namespace:System;assembly=mscorlib9adw1clr-namespace:Autodesk.Windows;assembly=AdWindowsCadiw:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindows-acr%clr-namespace:Autodesk.AutoCAD.RibbonKacmgdAclr-namespace:Autodesk.AutoCAD.ApplicationServices;assembly=acmgdCdata:clr-namespace:Autodesk.AutoCAD.Windows.Data;assembly=acmgdGdb@clr-namespace:Autodesk.AutoCAD.DatabaseServices;assembly=acdbmgdAcolors6clr-namespace:Autodesk.AutoCAD.Colors;assembly=acdbmgdResourceDictionary_1 ResourceDictionary_2$4./AcWindows;component/Ribbon/Controls/Base.xaml?ResourceDictionary_3$?9/AcWindows;component/Ribbon/Controls/ControlToolTips.xaml? %H\& & $& c& & & & H& {& & & /777777777& 7777& 7 7 7 7 7 7 & ^& z$& b%& j&& r'& s(& z)& *& +& -& $.& ./& ;0& {1& 2& r3777777777777& @=& 'I& _J& !K& "L7#7%& &_N777777& 'V7(7& )W7*7(& +X7,7-7.7/0StaticResource_7$">AcRibbonMenuItemSelectColors1ribbon:FontSizeConverter_1/+ribbon:ParagraphAlignmentToBooleanConverter""'#ribbon:ColumnTypeToBooleanConverter"".*ribbon:DynamicColumnTypeToBooleanConverter""-)ribbon:StaticColumnTypeToBooleanConverter"" data:Int32ToImageConverter_1.BitmapImage_10$>8res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_COLUMNS_NONE?BitmapImage_11$@:res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_COLUMNS_STATIC?BitmapImage_12$A;res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_COLUMNS_DYNAMIC? data:Int32ToImageConverter_2.BitmapImage_13$>8res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_COLUMNS_NONE?BitmapImage_14$@:res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_COLUMNS_STATIC?BitmapImage_15$A;res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_COLUMNS_DYNAMIC?,(ribbon:AttachmentPointToBooleanConverter"".*ribbon:LinespacingFactorToBooleanConverter""*&ribbon:NumberingTypeToBooleanConverter"" adw:RibbonMenuButton_1$ Justification$Vertical=$ Large= .$< 6res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_MTEXT_JUST $< 6res:///%prodname%btn.xmx/$10/$RCDATA_32_IPE_MTEXT_JUST  . .$ MTEDIT adw:RibbonMenuItem_12$ Top Left TL$0#Z$$TextEditor.AttachmentPointType8$1$ TwoWay=#Z$ TextEditor.AttachmentPointadw:RibbonMenuItem_13$ Top Center TC$1#Z$$TextEditor.AttachmentPointType8$2$ TwoWay=#Z$ TextEditor.AttachmentPointadw:RibbonMenuItem_14$ Top Right TR$2#Z$$TextEditor.AttachmentPointType8$3$ TwoWay=#Z$ TextEditor.AttachmentPointadw:RibbonMenuItem_15$Middle Left ML$3#Z$$TextEditor.AttachmentPointType8$4$ TwoWay=#Z$ TextEditor.AttachmentPointadw:RibbonMenuItem_16$Middle Center MC$4#Z$$TextEditor.AttachmentPointType8$5$ TwoWay=#Z$ TextEditor.AttachmentPointadw:RibbonMenuItem_17$Middle Right MR$5#Z$$TextEditor.AttachmentPointType8$6$ TwoWay=#Z$ TextEditor.AttachmentPointadw:RibbonMenuItem_18$Bottom Left BL$6#Z$$TextEditor.AttachmentPointType8$7$ TwoWay=#Z$ TextEditor.AttachmentPointadw:RibbonMenuItem_19$Bottom Center BC$7#Z$$TextEditor.AttachmentPointType8$8$ TwoWay=#Z$ TextEditor.AttachmentPointadw:RibbonMenuItem_20$Bottom Right BR$8#Z$$TextEditor.AttachmentPointType8$9$ TwoWay=#Z$ TextEditor.AttachmentPoint  adw:RibbonMenuButton_2$ Line Spacing$ Horizontal=$Standard= .$> 8res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_LINE_SPACING $> 8res:///%prodname%btn.xmx/$10/$RCDATA_32_IPE_LINE_SPACING  . .$ MTEDIT#Z$-'TextEditor.IsLineSpacingFactorAvailable adw:RibbonMenuItem_21$ 1.0x$0#Z$"TextEditor.LineSpacingFactor8$ 1.0$ TwoWay=#Z$%TextEditor.LineSpacingMultiplesadw:RibbonMenuItem_22$ 1.5x$1#Z$"TextEditor.LineSpacingFactor8$ 1.5$ TwoWay=#Z$%TextEditor.LineSpacingMultiplesadw:RibbonMenuItem_23$ 2.0x$2#Z$"TextEditor.LineSpacingFactor8$ 2.0$ TwoWay=#Z$%TextEditor.LineSpacingMultiplesadw:RibbonMenuItem_24$ 2.5x$3#Z$"TextEditor.LineSpacingFactor8$ 2.5$ TwoWay=#Z$%TextEditor.LineSpacingMultiplesadw:RibbonMenuItem_25$ More...#Z$TextEditor.MoreLineSpaceadw:RibbonSeparator_2adw:RibbonMenuItem_26$Clear Line Space#Z$TextEditor.ClearLineSpace  adw:RibbonMenuButton_3$Bullets and Numbering$ Horizontal=$Standard= .$9 3res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_BULLETS $9 3res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_BULLETS  . .$ MTEDIT#Z$#TextEditor.NumberingAvailable adw:RibbonMenuItem_27$ Off$ 100#Z$TextEditor.NumberingType8$0$ TwoWay=#Z$TextEditor.Numberingadw:RibbonMenuItem_28$Numbered$9 3res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_NUMBERS $ 101#Z$TextEditor.NumberingType8$2$ TwoWay=#Z$TextEditor.Numberingadw:RibbonMenuItem_29$Lettered#Z$TextEditor.NumberingType8$ 3:4$ TwoWay= adw:RibbonMenuItem_30$ Lowercase$C =res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_LOWERCASE_LETTERS $ 102#Z$TextEditor.NumberingType8$3$ TwoWay=#Z$TextEditor.Numberingadw:RibbonMenuItem_31$ Uppercase$C =res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_UPPERCASE_LETTERS $ 103#Z$TextEditor.NumberingType8$4$ TwoWay=#Z$TextEditor.Numbering adw:RibbonMenuItem_32$Bulleted$ 104#Z$TextEditor.NumberingType8$1$ TwoWay=#Z$TextEditor.Numberingadw:RibbonSeparator_3adw:RibbonMenuItem_33$ Start$ 105#Z$TextEditor.Numberingadw:RibbonMenuItem_34$Continue$ 106#Z$TextEditor.Numberingadw:RibbonSeparator_4adw:RibbonMenuItem_35$Allow Auto-list$ 107#Z$"TextEditor.IsAutoListEnabled#Z$TextEditor.Numberingadw:RibbonMenuItem_36$Use Tab Delimiter Only$ 108#Z$*$TextEditor.IsTabOnlyDelimiterEnabled#Z$TextEditor.Numberingadw:RibbonMenuItem_37$Allow Bullets and Lists$ 109#Z$#TextEditor.NumberingAvailable#Z$TextEditor.Numbering  adw:RibbonMenuButton_4$ Symbol$Vertical=$ Large= .$8 2res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_SYMBOL $8 2res:///%prodname%btn.xmx/$10/$RCDATA_32_IPE_SYMBOL  . .$ MTEDIT adw:RibbonMenuItem_38$ Degrees %%d$ 300#Z$TextEditor.DefinedSymbolsadw:RibbonMenuItem_39$Plus/Minus %%p$ 301#Z$TextEditor.DefinedSymbolsadw:RibbonMenuItem_40$Diameter %%c$ 302#Z$TextEditor.DefinedSymbolsadw:RibbonSeparator_5adw:RibbonMenuItem_41$Almost Equal \U+2248$ 304#Z$TextEditor.DefinedSymbolsadw:RibbonMenuItem_42$Angle \U+2220$ 305#Z$TextEditor.DefinedSymbolsadw:RibbonMenuItem_43$Boundary Line \U+E100$ 306#Z$TextEditor.DefinedSymbolsadw:RibbonMenuItem_44$Center Line \U+2104$ 307#Z$TextEditor.DefinedSymbolsadw:RibbonMenuItem_45$Delta \U+0394$ 308#Z$TextEditor.DefinedSymbolsadw:RibbonMenuItem_46$ Electrical Phase \U+0278$ 309#Z$TextEditor.DefinedSymbolsadw:RibbonMenuItem_47$Flow Line \U+E101$ 310#Z$TextEditor.DefinedSymbolsadw:RibbonMenuItem_48$Identity \U+2261$ 311#Z$TextEditor.DefinedSymbolsadw:RibbonMenuItem_49$Initial Length \U+E200$ 312#Z$TextEditor.DefinedSymbolsadw:RibbonMenuItem_50$Monument Line \U+E102$ 313#Z$TextEditor.DefinedSymbolsadw:RibbonMenuItem_51$Not Equal \U+2260$ 314#Z$TextEditor.DefinedSymbolsadw:RibbonMenuItem_52$ Ohm \U+2126$ 315#Z$TextEditor.DefinedSymbolsadw:RibbonMenuItem_53$Omega \U+03A9$ 316#Z$TextEditor.DefinedSymbolsadw:RibbonMenuItem_54$Property Line \U+214A$ 317#Z$TextEditor.DefinedSymbolsadw:RibbonMenuItem_55$Subscript 2 \U+2082$ 318#Z$TextEditor.DefinedSymbolsadw:RibbonMenuItem_56$Squared \U+00B2$ 319#Z$TextEditor.DefinedSymbolsadw:RibbonMenuItem_57$Cubed \U+00B3$ 320#Z$TextEditor.DefinedSymbolsadw:RibbonSeparator_6adw:RibbonMenuItem_58$)#Non-breaking Space Ctrl+Shift+Space$ 323#Z$TextEditor.DefinedSymbolsadw:RibbonSeparator_7adw:RibbonMenuItem_59$Other...$ 325#Z$TextEditor.DefinedSymbols  adw:RibbonButton_1$Find & Replace$Vertical=$6 0res:///%prodname%btn.xmx/$10/$RCDATA_16_TEXTFIND $6 0res:///%prodname%btn.xmx/$10/$RCDATA_32_TEXTFIND $ MTEDIT#Z$TextEditor.FindReplace adw:RibbonButton_2$ Undo$ Horizontal=$6 0res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_UNDO $6 0res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_UNDO $ MTEDIT#Z$TextEditor.Undo#Z$TextEditor.IsUndoEnabled adw:RibbonButton_3$ Redo$ Horizontal=$6 0res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_REDO $6 0res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_REDO $ MTEDIT#Z$TextEditor.Redo#Z$TextEditor.IsRedoEnabled adw:RibbonButton_4$Close Text Editor$Vertical=$D >res:///%prodname%btn.xmx/$10/$RCDATA_32_CONTEXTUAL_PANEL_CLOSE $D >res:///%prodname%btn.xmx/$10/$RCDATA_32_CONTEXTUAL_PANEL_CLOSE $ MTEDIT#Z$TextEditor.Close adw:RibbonButton_5$ Insert Field$Vertical= .$ Large=$= 7res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_INSERTFIELD $= 7res:///%prodname%btn.xmx/$10/$RCDATA_32_TABLE_INS_FIELD $ MTEDIT#Z$TextEditor.FieldDialog adw:RibbonButton_6$& Ribbon Button - Paragraph Button$ Paragraph$ Horizontal=$; 5res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_PARAGRAPH $; 5res:///%prodname%btn.xmx/$10/$RCDATA_32_IPE_PARAGRAPH $ MTEDIT#Z$ TextEditor.ParagraphDialog acr:RibbonCommandButton_50$Make Uppercase$ Horizontal= .$@ :res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_MAEK_UPPERCASE $@ :res:///%prodname%btn.xmx/$10/$RCDATA_32_IPE_MAEK_UPPERCASE $ MTEDIT#Z$TextEditor.Uppercase#Z$TextEditor.HaveSelection acr:RibbonCommandButton_51$Make Lowercase$ Horizontal= .$@ :res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_MAEK_LOWERCASE $@ :res:///%prodname%btn.xmx/$10/$RCDATA_32_IPE_MAEK_LOWERCASE $ MTEDIT#Z$TextEditor.HaveSelection#Z$TextEditor.Lowercase acr:RibbonCommandButton_52$Edit Dictionaries$ 606$Vertical= .$ Large=$> 8res:///%prodname%btn.xmx/$10/$RCDATA_16_EDITDICTIONARIES $> 8res:///%prodname%btn.xmx/$10/$RCDATA_32_EDITDICTIONARIES $ MTEDIT#Z$TextEditor.Options acr:RibbonCommandButton_53$ Import Text$2$ Horizontal=. .$Standard=$3 -res:///%prodname%btn.xmx/$10/$RCDATA_16_COLOR $3 -res:///%prodname%btn.xmx/$10/$RCDATA_32_COLOR $ MTEDIT#Z$TextEditor.Optionsacr:RibbonCommandButton_54$AutoCAPS$ Horizontal=. .$Standard=$3 -res:///%prodname%btn.xmx/$10/$RCDATA_16_COLOR $3 -res:///%prodname%btn.xmx/$10/$RCDATA_32_COLOR $ MTEDIT#Z$TextEditor.AutoCAPS$ TwoWay= acr:RibbonCommandButton_55$Combine Paragraphs$8$ Horizontal=. .$Standard=$3 -res:///%prodname%btn.xmx/$10/$RCDATA_16_COLOR $3 -res:///%prodname%btn.xmx/$10/$RCDATA_32_COLOR $ MTEDIT#Z$TextEditor.Options#Z$TextEditor.HaveSelection acr:RibbonCommandButton_56$Background Mask$0$ Horizontal=. .$Standard=$@ :res:///%prodname%btn.xmx/$10/$RCDATA_16_BACKGROUNDTEXTMASK $@ :res:///%prodname%btn.xmx/$10/$RCDATA_32_BACKGROUNDTEXTMASK $ MTEDIT#Z$TextEditor.BackgroundMask acr:RibbonCommandButton_57$Spell Check Settings$Spell Check Settings$ 605$ Horizontal=. .$Standard=$ MTEDIT#Z$TextEditor.Options adw:RibbonMenuButton_5$ Columns$Vertical=$ Large= . . .$ MTEDIT#Z$TextEditor.ColumnType8#Z$TextEditor.ColumnType8 adw:RibbonMenuItem_60$ No Columns$> 8res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_COLUMNS_NONE $ 200#Z$TextEditor.StaticColumns#Z$TextEditor.ColumnType8$0$ TwoWay=adw:RibbonMenuItem_61$Dynamic Columns$A ;res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_COLUMNS_DYNAMIC #Z$TextEditor.ColumnType8$2$ TwoWay= adw:RibbonMenuItem_62$ Auto height$ 201#Z$TextEditor.StaticColumns#Z$"TextEditor.DynamicColumnType8$0$ TwoWay=adw:RibbonMenuItem_63$ Manual height$ 202#Z$TextEditor.StaticColumns#Z$"TextEditor.DynamicColumnType8$1$ TwoWay= adw:RibbonMenuItem_64$Static Columns$@ :res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_COLUMNS_STATIC #Z$TextEditor.ColumnType8$1$ TwoWay= adw:RibbonMenuItem_65$2$ 206#Z$!TextEditor.StaticColumnType8$2$ TwoWay=#Z$TextEditor.StaticColumnsadw:RibbonMenuItem_66$3$ 207#Z$!TextEditor.StaticColumnType8$3$ TwoWay=#Z$TextEditor.StaticColumnsadw:RibbonMenuItem_67$4$ 208#Z$!TextEditor.StaticColumnType8 $4$ TwoWay=#Z$TextEditor.StaticColumnsadw:RibbonMenuItem_68$5$ 209#Z$!TextEditor.StaticColumnType8 $5$ TwoWay=#Z$TextEditor.StaticColumnsadw:RibbonMenuItem_69$6$ 210#Z$!TextEditor.StaticColumnType8 $6$ TwoWay=#Z$TextEditor.StaticColumnsadw:RibbonMenuItem_70$ More...$ 205#Z$TextEditor.StaticColumns adw:RibbonSeparator_8adw:RibbonMenuItem_71$#Insert Column Break Alt+Enter$ 203#Z$!TextEditor.IsColumnsEnabled#Z$TextEditor.StaticColumnsadw:RibbonSeparator_9adw:RibbonMenuItem_72$Column Settings...$ 204#Z$TextEditor.StaticColumns  adw:RibbonMenuButton_6$ More$ Horizontal=$Standard= ..$5 /res:///%prodname%btn.xmx/$10/$RCDATA_16_OPTIONS $5 /res:///%prodname%btn.xmx/$10/$RCDATA_32_OPTIONS  . .$ MTEDIT adw:RibbonMenuItem_73$ Character Set adw:RibbonMenuItem_74$Central Europe$ 400#Z$TextEditor.CharacterSetadw:RibbonMenuItem_75$Cyrillic$ 401#Z$TextEditor.CharacterSetadw:RibbonMenuItem_76$ Hebrew$ 402#Z$TextEditor.CharacterSetadw:RibbonMenuItem_77$ Arabic$ 403#Z$TextEditor.CharacterSetadw:RibbonMenuItem_78$ Baltic$ 404#Z$TextEditor.CharacterSetadw:RibbonMenuItem_79$ Greek$ 405#Z$TextEditor.CharacterSetadw:RibbonMenuItem_80$ Turkish$ 406#Z$TextEditor.CharacterSetadw:RibbonMenuItem_81$ Vietnamese$ 407#Z$TextEditor.CharacterSetadw:RibbonMenuItem_82$Japanese$ 408#Z$TextEditor.CharacterSetadw:RibbonMenuItem_83$ Korean$ 409#Z$TextEditor.CharacterSetadw:RibbonMenuItem_84$CHINESE_GB2312$ 410#Z$TextEditor.CharacterSetadw:RibbonMenuItem_85$ CHINESE_BIG5$ 411#Z$TextEditor.CharacterSetadw:RibbonMenuItem_86$ Western$ 412#Z$TextEditor.CharacterSetadw:RibbonMenuItem_87$ Thai$ 413#Z$TextEditor.CharacterSet adw:RibbonSeparator_10adw:RibbonMenuItem_88$Remove Formatting#Z$TextEditor.HaveSelection adw:RibbonMenuItem_89$!Remove Paragraph Formatting$50#Z$TextEditor.Optionsadw:RibbonMenuItem_90$Remove All Formatting$51#Z$TextEditor.Options adw:RibbonMenuItem_91$Editor Settings adw:RibbonMenuItem_92$Always Display as WYSIWYG$ 600#Z$TextEditor.IsWysiwyg#Z$TextEditor.Optionsadw:RibbonMenuItem_93$ Show Toolbar$ 601#Z$%TextEditor.IsShowToolbarEnabled#Z$TextEditor.Optionsadw:RibbonMenuItem_94$Opaque Background$ 603#Z$*$TextEditor.IsOpaqueBackgroundEnabled#Z$TextEditor.Optionsadw:RibbonSeparator_11adw:RibbonMenuItem_95$Text Highlight Color...$ 607#Z$TextEditor.Options adw:RibbonSeparator_12adw:RibbonMenuItem_96$Learn About MTEXT adw:RibbonMenuItem_97$New Features Workshop$60#Z$TextEditor.Optionsadw:RibbonMenuItem_98$ Help F1$61#Z$TextEditor.Options  "Ribbon Spinner - Oblique Angle$$Ribbon Spinner - Oblique Angle$ -85.0$ 85.0!..$9 3res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_OBLIQUE $9 3res:///%prodname%btn.xmx/$10/$RCDATA_32_IPE_OBLIQUE $ "1.0$ MTEDIT##Z$TextEditor.ObliqueAngle$ TwoWay=Ribbon Spinner - Tracking$Ribbon Spinner - Tracking$ 0.75$ 4.0!..$7 1res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_TRACK $7 1res:///%prodname%btn.xmx/$10/$RCDATA_32_IPE_TRACK $ "0.05$ MTEDIT##Z$TextEditor.TrackingFactor$ TwoWay=Ribbon Spinner Width Factor$!Ribbon Spinner Width Factor$ 0.1$ 10.0!..$7 1res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_WIDTH $7 1res:///%prodname%btn.xmx/$10/$RCDATA_32_IPE_WIDTH $ "0.1$ MTEDIT##Z$TextEditor.WidthScale$ TwoWay=Ribbon Text Box - Find Text$!Ribbon Text Box - Find Text8$$ %200Q$ MTEDIT&DataTemplate_1.R StackPanel_25 'adw:RibbonTextBox_2AcRibbonFindTextBox$$( Find text$) InsideRight=.*.+.,.$= 7res:///%prodname%btn.xmx/$10/$RCDATA_16_QUICK_FIND_TEXT -#Z$TextEditor.QuickFindText.+ContentControl_28|.-)Ribbon Radio Button - Paragraph Alignment$/)Ribbon Radio Button - Paragraph Alignment$ MTEDIT#Z$.(TextEditor.IsParagraphAlignmentAvailable.adw:RibbonToggleButton_9$ Horizontal=$#.AcDefaultAlignIPEToggleButton$ Default$/PA .$A ;res:///%prodname%btn.xmx/$10/$RCDATA_16_IPEDEFAULTPARAGRAPH $A ;res:///%prodname%btn.xmx/$10/$RCDATA_32_IPEDEFAULTPARAGRAPH #Z$#TextEditor.ParagraphAlignment8$0$ TwoWay=adw:RibbonToggleButton_10$ Horizontal=$ .AcLeftAlignIPEToggleButton$ Left$/PL .$< 6res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_LEFT_ALIGN $< 6res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_LEFT_ALIGN #Z$#TextEditor.ParagraphAlignment8$1$ TwoWay=adw:RibbonToggleButton_11$ Horizontal=$".AcCenterAlignIPEToggleButton$ Center$/PC .$> 8res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_CENTER_ALIGN $> 8res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_CENTER_ALIGN #Z$#TextEditor.ParagraphAlignment8$2$ TwoWay=adw:RibbonToggleButton_12$ Horizontal=$!.AcRightAlignIPEToggleButton$ Right$/PR .$= 7res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_RIGHT_ALIGN $= 7res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_RIGHT_ALIGN #Z$#TextEditor.ParagraphAlignment8$3$ TwoWay=adw:RibbonToggleButton_13$ Horizontal=$#.AcJustifyAlignIPEToggleButton$ Justify$/PJ .$? 9res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_JUSTIFY_ALIGN $? 9res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_JUSTIFY_ALIGN #Z$#TextEditor.ParagraphAlignment8$4$ TwoWay=adw:RibbonToggleButton_14$ Horizontal=$&. AcDistributeAlignIPEToggleButton$ Distribute$/PD .$B $TT_AcVisualStylesCommandToggleButton /?+AcDrawingRecoveryManagerCommandToggleButton 2@.TT_AcDrawingRecoveryManagerCommandToggleButton (A$AcDefaultLightingCommandToggleButton +B'TT_AcDefaultLightingCommandToggleButton #CAcLightGlyphCommandToggleButton &D"TT_AcLightGlyphCommandToggleButton EAcCameraCommandToggleButton "FTT_AcCameraCommandToggleButton !GAcViewCubeCommandToggleButton $H TT_AcViewCubeCommandToggleButton  Text ShowText IsEnabledBinding *I&AcLockedLayerFadingCommandToggleButton -J)TT_AcLockedLayerFadingCommandToggleButton )K%AcDrawingStatusBarCommandToggleButton ,L(TT_AcDrawingStatusBarCommandToggleButton &M"AcDynConstraintDisplayToggleButton %N!TT_AcShowDynamicConstraintsButton 'O#AcBlockConstraintStatusToggleButton PTT_AcConstraintStatusButton #QAcXRefFadingCommandToggleButton &R"TT_AcXRefFadingCommandToggleButton !SAcXRayModeCommandToggleButton $T TT_AcXRayModeCommandToggleButton 5U1AcVisualStyleIntersectionEdgesCommandToggleButton 8V4TT_AcVisualStyleIntersectionEdgesCommandToggleButton 1W-AcVisualStyleObscuredEdgesCommandToggleButton 4X0TT_AcVisualStyleObscuredEdgesCommandToggleButton 2Y.AcVisualStyleSilouetteEdgesCommandToggleButton 5Z1TT_AcVisualStyleSilouetteEdgesCommandToggleButton .[*AcVisualStyleEdgeJitterCommandToggleButton 1\-TT_AcVisualStyleEdgeJitterCommandToggleButton 0],AcVisualStyleEdgeOverhangCommandToggleButton 3^/TT_AcVisualStyleEdgeOverhangCommandToggleButton "_AcSunStatusCommandToggleButton %`!TT_AcSunStatusCommandToggleButton aAcBoldIPEToggleButton IsToolTipEnabled  Size#Autodesk.Windows.RibbonButton Orientation Mode bAcItalicIPEToggleButton cAcUnderlineIPEToggleButton dAcOverlineIPEToggleButton eAcAnnotativeIPEToggleButton fAcSpellIPEToggleButton gAcRulerIPEToggleButton /h+AcAdvancedRenderSettingsCommandToggleButton 2i.TT_AcAdvancedRenderSettingsCommandToggleButton "jAcRenderOutputFileToggleButton %k!TT_AcRenderOutputFileToggleButtonF9http://schemas.microsoft.com/winfx/2006/xaml/presentation8x,http://schemas.microsoft.com/winfx/2006/xaml@scm8clr-namespace:System.ComponentModel;assembly=WindowsBase1System&clr-namespace:System;assembly=mscorlib9adw1clr-namespace:Autodesk.Windows;assembly=AdWindowsCadiw:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindows-acr%clr-namespace:Autodesk.AutoCAD.RibbonKacmgdAclr-namespace:Autodesk.AutoCAD.ApplicationServices;assembly=acmgdCdata:clr-namespace:Autodesk.AutoCAD.Windows.Data;assembly=acmgdGdb@clr-namespace:Autodesk.AutoCAD.DatabaseServices;assembly=acdbmgdAcolors6clr-namespace:Autodesk.AutoCAD.Colors;assembly=acdbmgdResourceDictionary_1 ResourceDictionary_2$4./AcWindows;component/Ribbon/Controls/Base.xaml?ResourceDictionary_3$?9/AcWindows;component/Ribbon/Controls/ControlToolTips.xaml? %\B& & j& & W& & & >& & & >& & & Q& & & k& & ?& & & U& & & q& & 9 &  &  & F &  &  & h & & !7 7"7& #W 7$7& %7&7& '7(7& )7*7& +7,7& -7.7& /707& 1!727& 3747& 5767& 7787& 97:7& ;37<7& =k7>7& ?7@7 & A7B7& C 7D7& EQ!7F7& G"7H7& I#7J7& K5%7L7& Mk&7N7& O'7P7& Q)7R7& S1*7T7& UM+7V7& W,7X7 & YC.7Z7 & [/7\7 & ]17^7 & _l27`7 & az3& b4& c5& d37& eo8& f9& g:& h;7i7& j<7k*&ribbon:PaletteToggleButtonConverter_12$^C^C_defaultlighting 1$^C^C_defaultlighting 0*&ribbon:PaletteToggleButtonConverter_13$^C^C_lightglyphdisplay 1$^C^C_lightglyphdisplay 0C?ribbon:PaletteToggleButtonConverter_cameraToggleButtonConverter$^C^C_cameradisplay 1$^C^C_cameradisplay 0*&ribbon:PaletteToggleButtonConverter_18$^C^C_navvcube _on$^C^C_navvcube _off3/ribbon:LockedLayerFadingToggleButtonConverter_1$LAYLOCKFADECTL2.ribbon:DrawingStatusBarToggleButtonConverter_1GCribbon:PaletteToggleButtonConverter_xRefFadingToggleButtonConverter$ XDWGFADECTL*&ribbon:XRayModeToggleButtonConverter_1)%ribbon:VisualStyleIntersectionEdges_1$ ^C^C_vsintersectionedges 1$ ^C^C_vsintersectionedges 0UQribbon:VisualStyleIntersectionEdges_visualStyleObscuredEdgesToggleButtonConverter$^C^C_vsobscurededges 1$^C^C_vsobscurededges 0;7ribbon:VisualStyleSilouetteEdgesToggleButtonConverter_173ribbon:VisualStyleEdgeJitterToggleButtonConverter_195ribbon:VisualStyleEdgeOverhangToggleButtonConverter_1+'ribbon:SunStatusToggleButtonConverter_1$^C^C_sunstatus 1$^C^C_sunstatus 02.ribbon:SystemVariableToggleButtonConverter_201$!^C^C_dynconstraintdisplay 1$!^C^C_dynconstraintdisplay 02.ribbon:SystemVariableToggleButtonConverter_202$^C^C_bconstatusmode 1$^C^C_bconstatusmode 0 )%ribbon:PaletteToggleButtonConverter_1$^C^C_toolpalettes$^C^C_toolpalettesclose )%ribbon:PaletteToggleButtonConverter_2$^C^C_bauthorpalette$^C^C_bauthorpaletteclose )%ribbon:PaletteToggleButtonConverter_3$^C^C_quickcalc$ ^C^C_qcclose )%ribbon:PaletteToggleButtonConverter_4$ ^C^C_adcenter$ ^C^C_adcclose )%ribbon:PaletteToggleButtonConverter_5$ ^C^C_sheetset$^C^C_sheetsethide )%ribbon:PaletteToggleButtonConverter_6$^C^C_properties$^C^C_propertiesclose )%ribbon:PaletteToggleButtonConverter_7$^C^C_commandline$^C^C_commandlinehide )%ribbon:PaletteToggleButtonConverter_8$ ^C^C_markup$^C^C_markupclose )%ribbon:PaletteToggleButtonConverter_9$^C^C_externalreferences$"^C^C_externalreferencesclose *&ribbon:PaletteToggleButtonConverter_10$ ^C^C_layer$^C^C_layerclose *&ribbon:PaletteToggleButtonConverter_11$^C^C_lightlist$^C^C_lightlistclose *&ribbon:PaletteToggleButtonConverter_20$ ^C^C_rpref$^C^C_rprefclose %!ribbon:ParametersManagerConverter$^C^C_parameters$^C^C_parametersclose *&ribbon:PaletteToggleButtonConverter_14$^C^C_materials$^C^C_materialsclose *&ribbon:PaletteToggleButtonConverter_15$^C^C_sunproperties$^C^C_sunpropertiesclose *&ribbon:PaletteToggleButtonConverter_16$^C^C_visualstyles$^C^C_visualstylesclose *&ribbon:PaletteToggleButtonConverter_17$^C^C_drawingrecovery$^C^C_drawingrecoveryhide ($Ribbon Toggle Button - Tool Palettes$*$Ribbon Toggle Button - Tool Palettes8$<6res:///%prodname%btn.xmx/$10/$RCDATA_16_TOOLS_PALETTES $<6res:///%prodname%btn.xmx/$10/$RCDATA_32_TOOLS_PALETTES $ TPSTATE # Z $$ SystemVariables[TPSTATE].Value8 -)Ribbon Toggle Button - Authoring Palettes$/)Ribbon Toggle Button - Authoring Palettes8$?9res:///%prodname%btn.xmx/$10/$RCDATA_16_AUTHORPALETTE_NEW $?9res:///%prodname%btn.xmx/$10/$RCDATA_32_AUTHORPALETTE_NEW $ APSTATE # Z $$ SystemVariables[APSTATE].Value8 +'Ribbon Toggle Button - Quick Calculator$-'Ribbon Toggle Button - Quick Calculator8$3-res:///%prodname%btn.xmx/$10/$RCDATA_16_QCALC $3-res:///%prodname%btn.xmx/$10/$RCDATA_32_QCALC $ QCSTATE # Z $$ SystemVariables[QCSTATE].Value8 ($Ribbon Toggle Button - Design Center$*$Ribbon Toggle Button - Design Center8$93res:///%prodname%btn.xmx/$10/$RCDATA_16_OPTCONTENTX $93res:///%prodname%btn.xmx/$10/$RCDATA_32_OPTCONTENTX $ ADCSTATE # Z $% SystemVariables[ADCSTATE].Value8 ,(Ribbon Toggle Button - Sheet Set Manager$.(Ribbon Toggle Button - Sheet Set Manager8$1+res:///%prodname%btn.xmx/$10/$RCDATA_16_SSM $1+res:///%prodname%btn.xmx/$10/$RCDATA_32_SSM $ SSMSTATE # Z $% SystemVariables[SSMSTATE].Value8 %!Ribbon Toggle Button - Properties$'!Ribbon Toggle Button - Properties8$4.res:///%prodname%btn.xmx/$10/$RCDATA_16_MODIFY $4.res:///%prodname%btn.xmx/$10/$RCDATA_32_MODIFY $ OPMSTATE # Z $% SystemVariables[OPMSTATE].Value8 '#Ribbon Toggle Button - Command Line$)#Ribbon Toggle Button - Command Line8$93res:///%prodname%btn.xmx/$10/$RCDATA_16_COMMANDLINE $93res:///%prodname%btn.xmx/$10/$RCDATA_32_COMMANDLINE $ CLISTATE # Z $% SystemVariables[CLISTATE].Value8 -)Ribbon Toggle Button - Markup Set Manager$/)Ribbon Toggle Button - Markup Set Manager8$>8res:///%prodname%btn.xmx/$10/$RCDATA_16_MARKUPSETMANAGER $>8res:///%prodname%btn.xmx/$10/$RCDATA_32_MARKUPSETMANAGER $ MSMSTATE # Z $% SystemVariables[MSMSTATE].Value8 -)Ribbon Toggle Button - Parameters Manager$/)Ribbon Toggle Button - Parameters Manager8$OIres:///%prodname%btn.xmx/$10/$RCDATA_16_MANAGECONSTRAINTSANDPARAMETERS_16 $OIres:///%prodname%btn.xmx/$10/$RCDATA_32_MANAGECONSTRAINTSANDPARAMETERS_32 $ PARAMETERSSTATUS # Z $- 'SystemVariables[PARAMETERSSTATUS].Value8 .*Ribbon Toggle Button - External References$0*Ribbon Toggle Button - External References8$D>res:///%prodname%btn.xmx/$10/$RCDATA_16_EXTERNAL_REFERENCE_MGR $D>res:///%prodname%btn.xmx/$10/$RCDATA_32_EXTERNAL_REFERENCE_MGR $ ERSTATE # Z $$ SystemVariables[ERSTATE].Value8 +'Ribbon Toggle Button - Layer Properties$-'Ribbon Toggle Button - Layer Properties8$4.res:///%prodname%btn.xmx/$10/$RCDATA_16_LAYERS $4.res:///%prodname%btn.xmx/$10/$RCDATA_32_LAYERS $ LAYERMANAGERSTATE # Z $. (SystemVariables[LAYERMANAGERSTATE].Value8 *&Ribbon Toggle Button - Lights in Model$,&Ribbon Toggle Button - Lights in Model8$82res:///%prodname%btn.xmx/$10/$RCDATA_16_LIGHT_LIST $82res:///%prodname%btn.xmx/$10/$RCDATA_32_LIGHT_LIST $ LIGHTLISTSTATE # Z $+ %SystemVariables[LIGHTLISTSTATE].Value8 $ Ribbon Toggle Button - Materials$& Ribbon Toggle Button - Materials8$?9res:///%prodname%btn.xmx/$10/$RCDATA_16_MATERIALS_PALETTE $?9res:///%prodname%btn.xmx/$10/$RCDATA_32_MATERIALS_PALETTE $ MATSTATE # Z $% SystemVariables[MATSTATE].Value8 )%Ribbon Toggle Button - Sun Properites$+%Ribbon Toggle Button - Sun Properites8$<6res:///%prodname%btn.xmx/$10/$RCDATA_16_SUN_PROPERTIES $<6res:///%prodname%btn.xmx/$10/$RCDATA_32_SUN_PROPERTIES $ SUNPROPERTIESSTATE # Z $/ )SystemVariables[SUNPROPERTIESSTATE].Value8 1-Ribbon Toggle Button - Visual Styles Mananger$3-Ribbon Toggle Button - Visual Styles Mananger8$>8res:///%prodname%btn.xmx/$10/$RCDATA_16_VS_STYLE_PALETTE $>8res:///%prodname%btn.xmx/$10/$RCDATA_32_VS_STYLE_PALETTE $ VSSTATE # Z $$ SystemVariables[VSSTATE].Value8 3/Ribbon Toggle Button - Drawing Recovery Manager$5/Ribbon Toggle Button - Drawing Recovery Manager8$?9res:///%prodname%btn.xmx/$10/$RCDATA_16_DRAW_RECOVERY_MGR $?9res:///%prodname%btn.xmx/$10/$RCDATA_32_DRAW_RECOVERY_MGR $ DRSTATE # Z $$ SystemVariables[DRSTATE].Value8 +'Ribbon Toggle Button - Default Lighting$-'Ribbon Toggle Button - Default Lighting8$<6res:///%prodname%btn.xmx/$10/$RCDATA_16_LIGHTS_DEFAULT $<6res:///%prodname%btn.xmx/$10/$RCDATA_32_LIGHTS_DEFAULT $ DEFAULTLIGHTING # Z $, &SystemVariables[DEFAULTLIGHTING].Value8 .*Ribbon Toggle Button - Light Glyph Display$0*Ribbon Toggle Button - Light Glyph Display8$;5res:///%prodname%btn.xmx/$10/$RCDATA_16_LIGHTGLYPHSON $;5res:///%prodname%btn.xmx/$10/$RCDATA_32_LIGHTGLYPHSON $ LIGHTGLYPHDISPLAY # Z $. (SystemVariables[LIGHTGLYPHDISPLAY].Value8 )%Ribbon Toggle Button - Camera Display$+%Ribbon Toggle Button - Camera Display8$<6res:///%prodname%btn.xmx/$10/$RCDATA_16_DISPLAY_CAMERA $<6res:///%prodname%btn.xmx/$10/$RCDATA_32_DISPLAY_CAMERA $ CAMERADISPLAY # Z $* $SystemVariables[CAMERADISPLAY].Value8 #Ribbon Toggle Button - ViewCube$%Ribbon Toggle Button - ViewCube8$71res:///%prodname%btn.xmx/$10/$RCDATA_16_VIEW_CUBE $71res:///%prodname%btn.xmx/$10/$RCDATA_32_VIEW_CUBE $ViewCube Display.$ NAVVCUBEDISPLAY# Z $' !CurrentViewport.IsViewCubeVisible # Z $, &SystemVariables[NAVVCUBEDISPLAY].Value8 .*Ribbon Toggle Button - Locked Layer Fading$0*Ribbon Toggle Button - Locked Layer Fading8$A;res:///%prodname%btn.xmx/$10/$RCDATA_16_LAYER_FADING_LOCKED $A;res:///%prodname%btn.xmx/$10/$RCDATA_32_LAYER_FADING_LOCKED $ LAYLOCKFADECTL # Z $+ %SystemVariables[LAYLOCKFADECTL].Value8 -)Ribbon Toggle Button - Drawing Status Bar$/)Ribbon Toggle Button - Drawing Status Bar8$@:res:///%prodname%btn.xmx/$10/$RCDATA_16_DRAWING_STATUS_BAR $@:res:///%prodname%btn.xmx/$10/$RCDATA_32_DRAWING_STATUS_BAR $ STATUSBAR # Z $& SystemVariables[STATUSBAR].Value8 51Ribbon Toggle Button - Dynamic Constraint Display$71Ribbon Toggle Button - Dynamic Constraint Display8$E?res:///%prodname%btn.xmx/$10/$RCDATA_16_SHOWALLDYNCONSTRAINT_16 $E?res:///%prodname%btn.xmx/$10/$RCDATA_32_SHOWALLDYNCONSTRAINT_32 $ DYNCONSTRAINTDISPLAY # Z $1 +SystemVariables[DYNCONSTRAINTDISPLAY].Value8 2.Ribbon Toggle Button - Block Constraint Status$4.Ribbon Toggle Button - Block Constraint Status8$B8res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_RULER_TOGGLE $>8res:///%prodname%btn.xmx/$10/$RCDATA_16_IPE_RULER_TOGGLE $ MTEXT# Z $ TextEditor.IsRulerEnabled # Z $ TextEditor.Ruler$ TwoWay= 3/Ribbon Toggle Button - Advanced Render Settings$5/Ribbon Toggle Button - Advanced Render Settings8$3-res:///%prodname%btn.xmx/$10/$RCDATA_16_RPREF $3-res:///%prodname%btn.xmx/$10/$RCDATA_32_RPREF $ RENDERPREFSSTATE # Z $- 'SystemVariables[RENDERPREFSSTATE].Value8 -)Ribbon Toggle Button - Render Output File$/)Ribbon Toggle Button - Render Output File8$93res:///%prodname%btn.xmx/$10/$RCDATA_16_RENDER_FILE $93res:///%prodname%btn.xmx/$10/$RCDATA_32_RENDER_FILE $ RENDER # Z $. (RenderEngine.IsRenderToggleButtonChecked$ TwoWay=# Z $. (RenderEngine.IsRenderToggleButtonEnabled!' MSBAML```RNWindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35R8clr-namespace:System.ComponentModel;assembly=WindowsBaseSystem.ComponentModelOKmscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e0891&clr-namespace:System;assembly=mscorlibSystemD@AdWindows, Version=2.1.0.0, Culture=neutral, PublicKeyToken=nullF1clr-namespace:Autodesk.Windows;assembly=AdWindowsAutodesk.WindowsX:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindowsAutodesk.Internal.WindowsEAAcWindows, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nullA%clr-namespace:Autodesk.AutoCAD.RibbonAutodesk.AutoCAD.RibbonA=acmgd, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nulljAclr-namespace:Autodesk.AutoCAD.ApplicationServices;assembly=acmgd$Autodesk.AutoCAD.ApplicationServices\:clr-namespace:Autodesk.AutoCAD.Windows.Data;assembly=acmgdAutodesk.AutoCAD.Windows.DataC?acdbmgd, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nullf@clr-namespace:Autodesk.AutoCAD.DatabaseServices;assembly=acdbmgd!Autodesk.AutoCAD.DatabaseServicesR6clr-namespace:Autodesk.AutoCAD.Colors;assembly=acdbmgdAutodesk.AutoCAD.ColorsWSPresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35^ZWindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\XPresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35MergedDictionaries SourceA;Autodesk.AutoCAD.Ribbon.SystemVariableToggleButtonConverter !dwfOsnapToggleButtonConverterB8Collections.Selection.CommonProperties.ImageTransparency$ TwoWay=$ Ribbon Toggle Button - DWF Osnap$& Ribbon Toggle Button - DWF Osnap$=7res:///%prodname%btn.xmx/$10/$RCDATA_16_OBJECT_SNAP_DWF$= 7res:///%prodname%btn.xmx/$10/$RCDATA_32_OBJECT_SNAP_DWF$ DWFOSNAP8 #Z $%SystemVariables[DWFOSNAP].Value8$ Ribbon Toggle Button - DGN Osnap$& Ribbon Toggle Button - DGN Osnap$=7res:///%prodname%btn.xmx/$10/$RCDATA_16_OBJECT_SNAP_DGN$= 7res:///%prodname%btn.xmx/$10/$RCDATA_32_OBJECT_SNAP_DGN$ DWFOSNAP8 #Z $%SystemVariables[DGNOSNAP].Value8$ Ribbon Toggle Button - PDF Osnap$& Ribbon Toggle Button - PDF Osnap$71res:///%prodname%btn.xmx/$10/$RCDATA_16_PDF_OSNAP$7 1res:///%prodname%btn.xmx/$10/$RCDATA_32_PDF_OSNAP$ PDFOSNAP8 #Z $%SystemVariables[PDFOSNAP].Value8 Binding_1#Z $5/Collections.Selection.CommonProperties.Contrast$ TwoWay= data:MultiReplaceConverter_1.2 data:CompositeConverter_1. #acr:BindableStandardConverter_1"X#Z $C=Collections.Selection.CommonProperties[Contrast].PropertyType2 Binding_2#Z $1+Collections.Selection.CommonProperties.Fade$ TwoWay= data:MultiReplaceConverter_2.2 data:CompositeConverter_2. #acr:BindableStandardConverter_2"X#Z $?9Collections.Selection.CommonProperties[Fade].PropertyType2 Binding_3#Z $71Collections.Selection.CommonProperties.Brightness$ TwoWay= data:MultiReplaceConverter_3.2 data:CompositeConverter_3. #acr:BindableStandardConverter_3"X#Z $E?Collections.Selection.CommonProperties[Brightness].PropertyType2  Contrast$' !Ribbon Slider - Underlay Contrast$Contrast$0Q$ 100Q$ 150$45Q8.$ Visible=$ ATTACH8!#Z $5/Collections.Selection.CommonProperties.Contrast$ TwoWay= Fade$# Ribbon Slider - Underlay Fade$ Fade$0Q$ 100Q$ 150$45Q8.$ Visible=$ ATTACH8!#Z $1+Collections.Selection.CommonProperties.Fade$ TwoWay=  Brightness$) #Ribbon Slider - Underlay Brightness$ Brightness$0Q$ 100Q$ 150.$ Visible=$45Q8$ ATTACH8!#Z $71Collections.Selection.CommonProperties.Brightness$ TwoWay=! MSBAML```EAAcWindows, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nullA%clr-namespace:Autodesk.AutoCAD.RibbonAutodesk.AutoCAD.RibbonD@AdWindows, Version=2.1.0.0, Culture=neutral, PublicKeyToken=nullF1clr-namespace:Autodesk.Windows;assembly=AdWindowsAutodesk.WindowsX:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindowsAutodesk.Internal.Windows:4Autodesk.AutoCAD.Ribbon.HideableDialogSettingsDialogRNWindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35WSPresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35^ZWindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\XPresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35F9http://schemas.microsoft.com/winfx/2006/xaml/presentation8x,http://schemas.microsoft.com/winfx/2006/xaml>d2http://schemas.microsoft.com/expression/blend/2006Hmc;http://schemas.openxmlformats.org/markup-compatibility/20063src%clr-namespace:Autodesk.AutoCAD.Ribbon?adw1clr-namespace:Autodesk.Windows;assembly=AdWindowsIadwi:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindows Window_1 Title$Hidden Message Settings$ 484$ 550$ 350$ 550 SizeToContent$ Height= WindowStyle$SingleBorderWindow= ResizeMode$ CanResize= ShowInTaskbar.WindowStartupLocation$ CenterOwner=. StackPanel_2.+=7Autodesk.Internal.Windows.HideableDialogSettingsControl- Name$$mHideableDialogSettingsControl'#adw:HideableDialogSettingsControl_1- Name$okCancelHelp_StackPanel StackPanel_1$ Right=$ 0,0,8,0q Orientation$ Horizontal=.+- Name$ okButton Button_1$OK IsDefault .$65$ 4,4,4,4q.$3-$ cancelButton Button_2$ Cancel IsCancel .$65$ 4,4,4,4q$4-$ helpButton Button_3$65$ Help$ 4,4,0,4q$5! MSBAML```D@AdWindows, Version=2.1.0.0, Culture=neutral, PublicKeyToken=nullX:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindowsAutodesk.Internal.WindowsEAAcWindows, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nullU/clr-namespace:Autodesk.AutoCAD.Internal.Windows!Autodesk.AutoCAD.Internal.WindowsOKmscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e0891&clr-namespace:System;assembly=mscorlibSystemF1clr-namespace:Autodesk.Windows;assembly=AdWindowsAutodesk.WindowsV9clr-namespace:Autodesk.Private.Windows;assembly=AdWindowsAutodesk.Private.WindowsV9clr-namespace:Autodesk.Private.Windows;assembly=AdWindowsAutodesk.Private.WindowsA%clr-namespace:Autodesk.AutoCAD.RibbonAutodesk.AutoCAD.RibbonA=acmgd, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nulljAclr-namespace:Autodesk.AutoCAD.ApplicationServices;assembly=acmgd$Autodesk.AutoCAD.ApplicationServicesRNWindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35WSPresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35^ZWindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\XPresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35DataType3-Autodesk.AutoCAD.Internal.Windows.ColorSymbol Color Path82Autodesk.AutoCAD.Internal.Windows.LineWeightSymbol PropertyValueTemplate0*Autodesk.AutoCAD.Internal.Windows.Property OrientationPadding  propColumn TargetTypeProperty Value71Autodesk.AutoCAD.Internal.Windows.PropertyToolTip TargetType RelativeSource AncestorType'!Autodesk.Internal.Windows.ToolTip View! ColumnHeaderContainerStyle DisplayMemberBinding CellTemplate>8Autodesk.AutoCAD.Internal.Windows.NameDescriptionToolTip TextAlignment,&Autodesk.Internal.Windows.ImageAlignerStretchDirectionTriggersPProperty PValue TargetNameXMaxValue] ConditionsProperty Value:4Autodesk.AutoCAD.Internal.Windows.ContextHelpToolTip NameP SourceNameF9http://schemas.microsoft.com/winfx/2006/xaml/presentation8x,http://schemas.microsoft.com/winfx/2006/xamlDAdSrc:clr-namespace:Autodesk.Internal.Windows;assembly=AdWindows9AcSrc/clr-namespace:Autodesk.AutoCAD.Internal.Windows.sys&clr-namespace:System;assembly=mscorlib9adw1clr-namespace:Autodesk.Windows;assembly=AdWindowsBadpw9clr-namespace:Autodesk.Private.Windows;assembly=AdWindowsBadwp9clr-namespace:Autodesk.Private.Windows;assembly=AdWindows0ribbon%clr-namespace:Autodesk.AutoCAD.RibbonKacmgdAclr-namespace:Autodesk.AutoCAD.ApplicationServices;assembly=acmgdResourceDictionary_1%6(*,+)(*,+)& & ' 77'z' DataTemplate_2".R Rectangle_5$10$10$ 0,0,3,0q$ Center= $1SolidColorBrush_9$ ColorDataTemplate_3".R Rectangle_6$30 $ SymbolHeightDataTemplate_1".R StackPanel_7$ Horizontal=.+ TextBlock_11$ Center=$ Symbol TextBlock_13$ Center=$0q$ 200$FormattedValue Style_1". Setter_22$0 Style_7". Setter_1ControlTemplate_1".R Border_1#z#z#z._ StackPanel_8$3q.+ TextBlock_14$ Bold"$6q $ Title *TemplatedParent+ TextBlock_12$0q  $ Hidden=$ Hidden=$ Properties *TemplatedParent+* Foreground+ * FindAncestor+"   GridView_18 .PGridViewColumn_1 $ NameGridViewColumn_28 TextBlock_15$$10 Style_2". Setter_2ControlTemplate_2".R Border_2#z#z#z._ StackPanel_6$Vertical=.+ Rectangle_7$5$ yHidden=$ mTitle TextBlock_9$ 5,0,5,5q$ Wrap=*TitleAlignment+ *TemplatedParent+*Title+ *TemplatedParent+$ mSeparator Rectangle_3$ 0,0,0,5q$1#777777adw:ImageAligner_4$ Center=$ Center=._$mPreview mPreview$ 5,0,5,5q$ Uniform=$ yVisible=*PreviewStretchDirection+ *TemplatedParent+*PreviewSize.Width+ *TemplatedParent+*PreviewSize.Height+ *TemplatedParent+* Preview+ *TemplatedParent+$mDetails TextBlock_10$ 5,0,5,5q$ Wrap=$ yVisible=* Details+ *TemplatedParent+ P Trigger_12 @Title$. Setter_26$ mTitley$ Collapsed= Setter_27$ mSeparatory$ Collapsed=P Trigger_10@ TitleIsBold.. Setter_24$ mTitle$ Bold"P Trigger_3@ ShowPreview.. Setter_9$mPreviewy$ Collapsed=P Trigger_4@ ShowDetails.. Setter_10$mDetailsy$ Collapsed=P Trigger_11@Details$. Setter_25$mDetailsy$ Collapsed=P Trigger_9@ ShowSeparator.. Setter_23$ mSeparatory$ Collapsed=P Trigger_25@AdjustPreviewSize.. Setter_49$mPreview#Z Setter_50$mPreview#Z Setter_51$mPreview*PreviewSize.Width+ *TemplatedParent+ Setter_52$mPreview*PreviewSize.Height+ *TemplatedParent+]MultiTrigger_1  Condition_1@ ShowPreview. Condition_2@ ShowDetails. ./ Setter_11$ mSeparatory$ Collapsed=  Style_8". Setter_36ControlTemplate_8".R Border_5#z#z#z._ StackPanel_9.+$ mBasicContentContentPresenter_2$ Bold"*BasicContentMargin+ *TemplatedParent+* BasicContent+ *TemplatedParent+$ mHelpContentContentPresenter_3$ 5,0,5,5q* HelpContent+ *TemplatedParent+$ mSeparator Rectangle_9$1#777777$ mHelpInfo mHelpInfo$ Horizontal=$5q.+adw:ImageAligner_8$ Center=$ Center=._ Image_7$=7AdWindows;Component/Resources/Images/helpicon_16x16.ico$16$16$ Center= TextBlock_19$ Bold"$ Press F1 for more help$ Center= P Trigger_21Z@ BasicContent. Setter_37$ mBasicContenty$ Collapsed= Setter_38$ mHelpContent$5qP Trigger_22$ mHelpContentZ. Setter_39$ mBasicContent$ Normal" Setter_40$ mHelpContenty$ Collapsed= Setter_41$ mSeparatory$ Collapsed= Setter_42$ mHelpInfoy$ Collapsed=P Trigger_23@ShowHelp.. Setter_43$ mBasicContent$ Normal" Setter_44$ mHelpContenty$ Collapsed= Setter_45$ mSeparatory$ Collapsed= Setter_46$ mHelpInfoy$ Collapsed=P Trigger_24@ShowF1HelpString.. Setter_47$ mSeparatory$ Collapsed= Setter_48$ mHelpInfoy$ Collapsed= lSystem.Resources.ResourceReader, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089#System.Resources.RuntimeResourceSetPADPADP!?ﻵvr-A4l = }kFXާ;._>,t^Gv!.BW +Ribbon-NAVSMOTION -QVDRAWING-QVLAYOUT"FError_Specified_Tab_Cannot_Be_Found-NAVSMOTIONXNAVSMOTIONCLOSEd PlusRibbonPromptuQVDrawingQVDrawingCloseQVLayoutQVLayoutClose RibbonRibbonClose+Ribbon -NAVSMOTION -QVDRAWING -QVLAYOUT)ERROR: The specified tab cannot be found. NAVSMOTIONNAVSMOTIONCLOSETEnter . of the tab to make active (e.g. ACAD.ID_TabHome) QVDrawingQVDrawingCloseQVLayout QVLayoutCloseRibbon RibbonClose)lSystem.Resources.ResourceReader, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089#System.Resources.RuntimeResourceSetPADPADP{vNF#CloseInfoCenterTestInfoCenterCloseInfoCenterTestInfoCenterlSystem.Resources.ResourceReader, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089#System.Resources.RuntimeResourceSethSystem.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3aPADPADCPlayMaskImage@ QSystem.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3aSystem.Drawing.BitmapData  PNG  IHDR>asRGBgAMA a cHRMz&u0`:pQ<IDATx^k0 {l̓0+}Sŏ`j8\/G1xz^~W;8 {C&<  AFy=e2~zzA6@Suj P  9 }d2V1Y` `k !@bۑRj>@P0 8 _f)(hB ] (' hxUH(В=BP{n=ճ*BHĭ XdeZHhe=0Z=ǫV& J ([1NdY,@ kcwghhE(++++,- J@i4P( 聞SVFD`V^s;)gl0k@zK0=O`Zox g ` P-D>a j%u`]' 0@D` ѳk0a.)=p%C||jLip)pkĻ/ 4?:Xs;pH(IENDB` Y0lSystem.Resources.ResourceReader, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089#System.Resources.RuntimeResourceSetPADPADPΫǁ‘e#KRmiN ֆ/67뎙8;*A7gw.KI( fEՏWSY3מEݢI!ФfUJtOM օӼмužԏI~Av4ôaxsێ{k$S'ǯNjaL,ɐʴt0˕̈́I/J/Z/Z/I/+/кVL<٤P\$-)߰1+5RU)#==*df^ʚ:eq9zMgl$op #'#&R9/dw: ޘg bÇ *nV[EcKs ] ]D!~q$]&(=7*F1ɔ2t55GW66:N-0P}0P8;U^6VgڇW4?Z(I\&\\{g-i imPk˝}m~2nըpg=qgrmr+ʪr]utϼvWvzeC||[؀||oт|> TW4   41  +Sr`ou }(AD# [u 3 T  Fr Zq $ < M * &29 u %@Z |G0>\7w7dd[_U {b)Q j ^)aL oc S Active>AnimationResumeRecordingToolTipMigrateRibbon_Balloon_MessageID6MigrateRibbon_Balloon_TitleMillimeter2MyAutoCAD_Balloon_AppName6MyAutoCAD_Balloon_MessageID-.MyAutoCAD_Balloon_Title?NoneQOtherLineTypesW.Output_SpecifyImageSizea4QVMenuCommandSDINotAllowedy.QVMenuMenu_ArrangeIconsQVMenu_CascadeQVMenu_CloseAll(QVMenu_CloseFILENAME,QVMenu_CloseOtherFiles.QVMenu_CopyFilesasaLinkQVMenu_SaveAll,QVMenu_SaveAlltoFolder.QVMenu_TileHorizontally *QVMenu_TileVertically" BQV_BeditLayoutOptionsNotAvailable3 RibbonService_DynamicHelp_Panel :RibbonService_DynamicHelp_Tab SMMenu_All# SMMenu_Delete) SMMenu_MoveLeft2 SMMenu_MoveRight= SMMenu_NewViewI "SMMenu_Properties] SMMenu_Renamem &SMMenu_ThisCategoryu SMMenu_ThisView 2SMMenu_UpdateThumbnailFor NSMRenameErrorTaskdialogTitleForCategory FSMRenameErrorTaskdialogTitleForView &SearchCommandLoaded (SearchDropDownFlyout SearchFlyout $SearchGroupAppMenu SearchGroupQAT "SearchGroupRibbon SearchPanel SearchPanelFound) SelectColorB Select_ColorsS Singlee TT_Modelm TT_NoThumbnail TT_QVD_CP_CLOSE TT_QVD_CP_NEW TT_QVD_CP_OPEN TT_QVD_CP_PIN TT_QVD_CP_UNPIN TT_QVD_TN_CLOSETT_QVD_TN_SAVETT_QVL_CP_CLOSE$TT_QVL_CP_NEW>TT_QVL_CP_PINJ"TT_QVL_CP_PUBLISHbTT_QVL_CP_UNPINnTT_QVL_TN_PLOT"TT_QVL_TN_PUBLISHTT_SM_CP_CLOSETT_SM_CP_LOOPTT_SM_CP_NEWTT_SM_CP_PAUSETT_SM_CP_PINTT_SM_CP_PLAYTT_SM_CP_STOPTT_SM_CP_UNLOOPTT_SM_CP_UNPINTT_SM_TN_GOTT_SM_TN_PAUSETT_SM_TN_PLAY# TT_UnInitialized)TT_UpdateThumbsq@TableTabCustomCelltypeItemHeaderThreeAboveThreeBelowThreeHorzThreeLeft ThreeRightThreeVert'TwoHorz8TwoVertI WhiteX Yellow_*Active Model Configuration*Resume Recording AnimationStart Recording AnimationBlock Definition NameBlueNoneContent SearchCyan  {1} {2} ? {0} {1} -Please enter a value in the range: {0} - {1}.Illegal characters.Exit {0}Chttp://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=1109794"Object is not a FontName or String Four: Equal Four: Left Four: RightUse Large Icons Show LabelsSwitch to Gallery ButtonGreen Hello, world!AutoCAD Please provide a positive value.Manage Layer States...New Layer State...Unsaved Layer StateAllDocked Toolbars/PanelsDocked WindowsFloating Toolbars/PanelsFloating WindowsMagenta Best MatchesRelated ResultsMigrate2009RibbonBalloon acad_aug.chmMigrateAndTransferCustomizationCUIRibbonMigrationBalloon1Ribbon customization must be manually transferredmm Initial SetupMyAutoCADBalloonPartner ProductsNoneOther...Specify Image Size ...#Command not allowed in the SDI mode Arrange IconsCascade Close AllClose Close Other FilesCopy File as a LinkSave AllSave All to FolderTile HorizontallyTile Vertically9** Layout options not available while editing a block. **9** Layout switching not allowed while editing a block. **#Command not allowed in the SDI modeDocuments QuickViewLayouts QuickViewShowMotion QuickViewQuick Access ToolbarRedSave rendering to file: OffSave rendering to file: OnAll Image FormatsRender Output FileInvalid file nameManage Render Presets... BMP(*.bmp)JPEG(*.jpeg;*.jpg) PNG(*.png) PCX(*.pcx) JPG(*.jpg) TGA(*.tga) TIF(*.tif)Update Render PresetShow Related Tool Palette Group Allow Docking Anchor Left <Anchor Right >MinimizeNoneClose Customize...HelpNonePanelsShow Panel TitlesStretch to Window WidthTabsTool Palette GroupUndockRibbon drop-downpaneltabAll Delete  Move left Move rightNew View / Shot…Properties... RenameThis category  This viewUpdate the thumbnail for category view Command Loaded: {0} {0} FlyoutFlyoutApplication MenuQuick Access ToolbarRibbon Tab: {0} {0} PanelRibbon panel found: {0}Select Color...Select Colors...Single Click here to go to model space.&This thumbnail preview does not exist.Close Quick View DrawingsNew...Open...Pin Quick View DrawingsUnpin Quick View DrawingsCloseSaveClose Quick View Layouts New LayoutPin Quick View Layouts Publish...Unpin Quick View LayoutsPlot... Publish...Close ShowMotionTurn on Looping New Shot...PausePin ShowMotionPlay allStopTurn off LoopingUnpin ShowMotionGoPausePlayFThis layout has not been initialized. Click here to go to this layout.LTo generate all thumbnails in this drawing, run the command UPDATETHUMBSNOW.Custom Table Cell Format ... Three: Above Three: BelowThree: Horizontal Three: Left Three: RightThree: VerticalTwo: Horizontal Two: VerticalWhiteYellowBSJB v2.0.50727l4#~#Strings/;H1%1 1 11] ,2 2 k4 4l555&6&7[*77"L9&9"9:"::"::4<<"M<:?1?;?k?kSBuB|B_CE;iFHH;JJKJcM;"NNN|R*17NU;aU;~UU"UOV-V"VtEW-V"ZN^[0^[^^M_}__ q`Db%b^b;bb"Nd%ddd d ef g Hg g "h% 7h 7h'Jhg _h _h? nh nh~h@i-V"i k l :mmm` &n Cn"n n"p>p;"mp"p"p"[qr-V"rN"rt s t"v%.x x}y;yJyy y  )z )z Zz mzt zz z z{s{{&|||}^~J"""L" X ΃ g   ;΃ g&^-V;yԔ-Ԕ$%baԔԔԔԔ͢;;"B/Vee2ϣe""")"x"  "8t"Ht;ޥ"%.ͦ-V ^"1^Wb c ǧ0D}[&˨v]   s%b%b%b%b%b%[a<. x. x;(6 6 @ N'. &׭" " \^n^&®&®&®& ®&-®  ݯ   7;jr;"" "bt"ṯ""":]"$NT &[b O +"J%bᴉq%b"zN"㵱N Ӷb"!'.>[&U"fe"""ط"귻""CN]Ԕ&& ?N;;ٹ%1;#b?*Ϻٺ-V"^`-V-VӼ-V-V-V**7#7^%1``׽;`;);C;_``;;; =;X%1&ٿ/"'U<""*X7"sŠŠ!1B`V!­&%É,ÊÊ-V6G2626L2Z/ &T<k;;&ʼnŲ"&""8t"Pt"t"ǜ:"Ȝ:>;"gȜ:'-;6ɭٲ gڭڭۭ&ۉ'ۉ(܉[܉`݉݉މBމ"Nމ މ t  -  o߉""v ""0]""/""""""7"k"""5Y-V"N"N"t"t"N"N"L  x"N  *]|;<މ"W; &"~U"""%"%  '%1. x. x^&s{``;``!`@-V"K"vNeK"d"-V*-VI-VZ-V"u-V -V+*!:*c7%b%b%b%b"N d""N&$>;_&&" *&+w-V-V-V-VԔԔ%G e% p%~%%) 1 5%9%9%=%!=%%E%'L %'f0%!(hM%)l`%*rz 7%7-78%1:-%5;B>\9>i!Es GG9GH1K1L N! NEN*IV2C_-eC`3wCfACYgTCYjY%m_% vk%voyu{z3{~O}`xa 1I&1&*1- 0) 4A 8\i<j aei   # / ?Q_d m #-*-M\6f\=x\B\H\J\NR%b(b*g-m-o*q.vBy/S}0j0048::%<%F%G %G %I/ %N? %O S %Rg Rx n y 1z | %}   ! ! ( ? W q       ! G v      E b      $ 'M *] * - 0 4 8 ; >A$D?GTJpOSVY\_)dA!g[qlt{!wm%I%%+%7%MZav%%%%! %%%%"!%'2%)_AIV O e U fZ gi kqou- u)./CPdp}<CAF/)NVVV`VlVzNVzVVVM^c 6 dX&s&z&&&&&&&&&'''j((O)e)&):):6-*+!+!+!+!+,6-,x,x-NV-V--. .%. 6c.6..,/?//// 00.0<0I01xU1|_1|1112282A24:v5 555v5 56666666@6E6?7^_7p7|(7J8Z8;3;8<<H<=`6x>>g????????F@S@Th@Qr@Q}@Q@F F F G )G :GGG SG ^G lGG GGGGGGGHH"H1HDH THaHoH |H H HH H HH I5NVI VI VI VI I ?I. .II6KJ6wJ6J6?6J65K6yK6K6K6-L6_L6L6L6"M?IM] bN5P GPNVlP VP VP VP VP VP VP VP VP GPQ(QNQSTT2TDT VT dT qT# TT T T( TTNVU8 VU8 NV-UG V1UG NVU VU VV - V V V<=bWX J8X%X @XQXX= =;YNV^Y VgY VnY NV-U V1U V.[ [f\\\\\ \\NV0] V:] ]]]4 ]` '֯5^ ` ^ `s&$`^ aaa2ab^ bUDeYQec`emfeveere|e|eeyghfehhrfevehiR],>Wo=>RN>X>b>m>>>߀>W>RK9 >l >ld9Z/ ?sL$?y9:?:N?i ;g? |?i; PRRK@RX@ @ 8(<<@{@ @ @!A!A"-A"FA#łUA#ЂeA#pA#yA#A$(PA$$A$A$=A$=9&Ah(!A*,Bh,$Bh.3B0$CB2T?_B4?B 5h@B 6PB7B9B ;hB <@ C <C?\A0CAAGC& CEsC- DC5 F̆C5 G܆C< HFCF JCM KFDL G*DN\CDPH^DPmDRÇ|DSDUHDU0JDWDWЈDT WJDWYpKD^ YMEhZ#E\EE^[Eh^uE`Ec `LEi `dNEt clOEpcEe̊EfEgPEz iXF j+Fl(P~RI~R ~S- S-S8S J@SJ  S # + ]JjJ+09 =0? KJ]Jkb>}m> KF !KL OKF dKL ЍKF KL KKK"L5ALS BPLUPzLbLpLLMWMR;MWOMRN>I-QmMW S Mb X Mb qZ/S Piy jN wNN(P P ֏NޏNN 80CUAAVN Oΐ%Ohא8OhMOhdOhrOhOhOh OhOh O XEc Y@OhБOhPhp!Ph  NNN 80CYAAZEc Ò@PhXQhPh!Ph ;Q , A[\QqQi7QiFQi XQi Qi QiQiRiЕRi,Ri@RiLSRi0C3B4^fRi!_R #^A%pR '$bB)cEc +×Rh0TRh2lRh4Ph6!Ph8PeS:i)S:@S ; QS;gS;}S<&S</S=>S=NS>VS>?AACDFFHIK- LOPRRT`4UL UtUT VUc Z1Up ]<U} `LjU djU jU nܚU o6- p>"VpG p kXV qXnVrVirțVit8vVv%V v< vkWyl"Wyl8WylYW y%8{ {Wi|0W~8~@m~8 o88W yW  pW  P @ WT]I ר]T _T'gT''^  ] p>^ C^ P^ d^ ąp^ N֥54x^i^ d^I^ Ʃ^ !ө _ " _ #1_$ E_U$H P%e_ %_ '_))_i)_i+_-pT-+`i-T/ N`i/# _ 1< _ 2U^ 3E_U4]5`i7`9«`9׫`9$i9T _ ;T _ <T=TU=T >Uj @U`@9U`AAU aAcUaS BkU5aUBtUMa+CUVaiDU^ FtE_UGUdaS HUqaHU}a HaIaIBbJJbJpMa+KNb5Lcb>MqbGNĬOUVO̬NO _ Q _ R^ S3E_UTb PUb UbxUbYV b`W4bYXtcgYcgY0crYЮCcrYYcxY,ocxYXc}YcYc Yc`Z0c[`Vc^ d^t da1dbcܯ`dgrdgdgdgxdg dh4dij$dk\dlemVe*q)e=u|!JvMaxܰfyfzfz(g|!g}5g ~@cgNd<gd$d0`g<g9gE<(hMȱdV$dbdn,dzdd̦d̲ddLhTh]`dehNndhȳ`dгrdسhiQQ Ii@`i~ri(Pi(Pii&Դ^,Fi,i3i3X j3%j3liii(P PijZzjZjZjZV j W j  W j 9W k RW %k kW 8k W _k W tk W k W k W k X k X kq3X lqܩ %$qEBqi!wqM#oi%qi'qi)qi+6ri-M!ri/d>ri1]rQ3żiQ5мQ7Q9,}r;k9=7rU?Br]AMseCX_$aE$aGoYI2;iKM;iMν4siO$iQֽWsiS޽sUsmUswXs\Xsa<scsddd%ue-u e6fY#v-hY5v-h"YvMhzjTzsz|zzzDztz*{B{@Z{{h{{t{,MaD!MaTMa MaMa#TMa/<Ma; |G B|X V|X}|jG|_Y|el|W|R|W|R|W|R<_) P_}q+}<}M}^}jt}j<_\ P}rT}zNZ,\Z,NdZ,\Z,NZ,\Z,N(}0}9~A~L g,x, Ne~x~,,N,,,N d, ,$N(,(,,N0,0D,4N8p,8F,<N@,@\Z,DNH,H\Z,LNP,P\Z,TNX,X\Z,\N`,`T,dNh hiP,i\Z,mNq,q\Z,uNy,[,y~}\Z,~$~N,,N,,N,\Z,N&0S .0UN7*r\DdVm,m,xN,(,N,T,N,\Z,N,\Z,NF,,NF,,$iN=!jK@,S,N,S,N<,S,N,S,NF,\,   NF,T,Nj j/ A,O; aJo,, $0 P$F,$,(N,F,,,0N4 B|X4 V|X5Z/6oS 7 zU7S 8U8(j9TK;<_= P==́=܁=> >'?X@7/BEBKBVB6<*BP7/B|EBKBVBB<Bh0B`#C/D8D9iDSF=H(P9 Hk9J[L|[M1S N>NN(PChNTLhPQhRX[5T5T PV[߃V[V[V[EX[Y\Y \Y PY\@Y%\N Z3\\\E\i]S\v:_[\"_d\)`l\4`u\Ąa}\҄ap!S b!@bNc\Qhcune(hwf\hNi Pii i]ik$]؅k0]k=]lI] lV]m^]-mg]@no]Pnx]`o]xo]p]p@/qM9 rNsZ Ps|C}sQ}ss(P1sNsPs @s`4UuNv _ v _ wU^ x E_Uyчz臠zNz"Uz1o{9{A{  U{`| $}b~~ P~4  P~~]h]2$^HS 1^YU?^jQ^y_^q^^:^"^^ɉ^։^S U*1A P^^=6_G_Q._`o<_D_U_f_n_w_0S _0U__ S ыD_[jD,rN,{u.8Ca__~___ȌiVxW P_=6_G_ ` `'b0`:hC`hbU`M[c`You`iu`|``Ž`Ύ`ڎ``a a)a,NaTaa #>1WEnYmА %9P j!(8Α\   ) 5 A O \ i z 8   iaya!-4BaŔIaSa^aja7ubGSbibibibikt}}bibibibiŕ̕ԕܕ(4@GV]hnwS)wS)ÖΖזΖזΖזΖזΖ%זÖז1;DDDÖDIIQזVז`זfזQזQזQזΖnwזΖnwfזnw`זΖVזnwfnVnVn`Df`kbibibiǗҗ1@DLT]fmpDLT]f1DLT]fDLfbibibibibibibibibibibibibibibi~DLT]fDLT]fDiŘbibibibi˘֘ܘ˘֘ܘiibibibibiiiiibibDbibibibibibibibibibib !&/8AbibibibiP]biP]dnvdnvdnv|bbÙʙbibibibiϙۙbibibibibibibibibibibibibibibibibibibibiiibibibibi]T IÙ!+2ϙۙbibibibibi>ŘDHLbibiPUŘbibiYbi!!!UbgbibiŘbijs{bibibiUŘbi>ŘUUbbibiʙP]P]>Ř>Řɚbibibibi>ŘibibiҚٚIbibigbibibibibibibibibi!bibibibiIbibi!bibibibi#/Ibibibibibibibibibibibibibibibibibibib!bibibibibibi+/2=P[f=v=v=ʛʛڛڛbibiŘbiݛbiŕŘ Ù bi"bibibibibibibibibiii-:ʛʛ:@::::K"VKVKŘ\!afiivڛiibiVܘܘhhhhhhhŘƜ˜ММڜacbiwbibbbibibibibibibi+++#.=NQN!QRXj@ry@@apʝpʝӝpޝ##)#:I:Q::+`dbibir+:::::~::::pʝpʝbibi]]bibibibižɞbiǗОٞbi!bibibibibibibibi,Qbibibibibibibibibibibibibibibibibibibibibibibibibibibibibibibibibibibibibibibi2bi2bi=2bi=EbiETbmqwQibizzŸzmq؟zmqQQbim"");M");MXccjr}hQq ˠՠQՠQՠܠՠՠՠՠՠՠi++bi!ܘܘܘܘܘܘܘܘܘܘܘܘܘܘܘܘܘܘܘܘܘ ܘܘ ܘܘ ܘܘ ܘܘܘܘܘܘܘܘܘܘܘܘܘܘܘbiܘܘ$ܘܘܘܘܘܘܘܘܘܘܘܘQbi0:biDܘܘܘܘܘܘܘܘܘܘܘܘ+i+iܘܘܘܘܘܘK+i+X[bibibibiiibibibiP]aceqqtqqtxrrbibibbb``biš͡šܘšܘءžɞžɞɞ žɞŕac$(.ɞɞžɞžɞaܘ5]ܘ5]ܘB]OW]OA'M(Q)U*]+]7]7eWAduhuiuluuz}AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA]Mu 6 6   H ^!¤4ݤ) ,1 C1,C9`jA9_1nY911DإQ[)D^LY T9%\G8!ddL^!SF\d631m}1111iԦxqGqiY0y"yzU9=lإ 9GS Yp}h9 [b̧ݧY0[Y![;KVEl^dcit|9 G8@AI3It^t?EUl9 G8iiꨈ ".BVfYt9%G8.Vdl@Aé) 1թ1 110 A1J&1^, 8 ?! i}g) pui ;,i1 1iE|iQ9 [iQA hmyA YaI IIӫIޫQ Y >^i i iKA q Dy Ve i) wpl)YH)3 }YI "Y09UYUYɬS YլYYIDY"Y Y#l/L 9%G8^d }m9G =6 9 G8o0=6}dL9%G8d9Gddإ)ɭ 9 G8  ɭ H) ^z  ^Y0bYS bb G }YɭY` 3+Y?U9G 9% G8^ d1i+ 0)iAiLi 箃iWiA d I o #u 3i?iGO^j1=61H9zS 1 S =6 [S Yi įѯa}Y11^YMa+Y11)1O91 1 Q A5 AA< A)D Y I l  аٰQQ !)_ :+ JY 9 a 9 i    y B|X$ bx / DxZo  إ,,إT!ܲ 1 1H),g!rd!) !)`d))*! C0! 9Ij6! zAH) },^)(H((Q\jqx(a() ¼(aܼ(1 9(I D,~1 (Q (Q (Q (q#-M(q--'S q0a M(0i ji pz)q  ))0Ľ)")()4.)O4) :)hWq u ) J) WWi .d)$/1i i #-i N/8Z/¾q)Ͼ1 Uw)A U A )1 )A &.0) O)A c)mWxRR )) [ qA  )))) *(*24* AL :*^A*䨠k p)T*)[* a*  h*!  m*#C;) ]r*1 {r* x*! l k29 Q *a EI 5*Q *Y Y Jœ*A*Y z[Q /**I꨽*i _*i /*i*i*63qiqu š š šiEz š+iz) p š š š }a+ š Ú+  y 4 +qAE 3 3y \2+ l8+i=+!t!i J+)Ý)Ú)Ú)6)Úi P+11 i  i}aii1 4Y+q)g+ Ŋr+ i +Ac)Aw:IA"Ļ+ + z "J+,48  9إ [S yT,[,q )  b,  i,i,'ƹ)3 x# Ip,bƠEagaisu,W {,Ɨ  "ǂ,`j,wǏ,!ǖ,ǗǗ)ȝ,12Ȥ,Iȱ,Xȷ,pȾ,}{,ȗ Ȃ,ȏ,Ȗ, !ɗ3ɗEɝ,Vɤ,I e,` u,,Q9G,Y- ɗ Z/RQ 9P-(P-iE iVZ-ch-ij xr-9%G8ʁ-dc-ʲʁ- y-y- }.-ˬ.yE.c.o..}3/Wyc.|WWWI ˎ/I oW!j)Q ^/ .' X/){)0̿AWAWc C0H0&O0 GV0^ ve0i,e0C0WZ/Q  ͆000Ͳ0إ^0U 0 0I!UIc)))0)E)X0)i1y1)&1)#Iβ)^ iIs1i}1)σ1aϣ1Yiy1I 9i2i2Ah %2i63a&о(i.2iEiQ ih i{ i Yya;2a;2aB2РG8 i  Ѡ "  Ѡ Ѫ2) x#) $B2]ѳ21o2p2 u2^2R2mW|WR3ѠѠ ҠҠqrd %җ iia<^ QҚ)YpҠYY ҚY2I ҡ3 Yp,a }إPҚ, YӺ3 (dG3P bӚ Ӛ Ӛ Ӛ y3y7yIyFB2yTyd) {4y849F4GL40(Mizd}as4 ;, ;, z4y2 [41 !R՞4` !dզ4r xմ44|տ44444 W49AI+'5I=Qf-5oxv75J5Y >^Z5^a5q >^g5q Ŕ֎5֗59 Թ5 5)9%G8yd$59%,G86,d\"6q q (6q >^.6%56W@6b~  C ؉6I 9!S I 9   a6i66M6iS }a w 6 Ci?69i}a Y 470 D T i7 x7/' Y Ma+YVai9+7907 P qaԸ0x#Y1`7YCYcbn7^ E_U)\ۗ<)n~7 ۠&99z"37i97D^D9 LG89o:TT^98\^48ddH8\T9 i l A0 G   ې8 ܖ8tt^ ?Ulg|gD8||m|^u8llml^|9Gdd9 G8 o#dgiGu,  Ma  $n9 5t9F{9 S݁9 }ݑ9ݚ^g!9 9Q)^9^9 G8!^9gGܖ8?U,9:9Vd?: q 9+7޾1}6! S:QI}6!a :!ޚ:!!!!1G#߭:qY<߳:qEB2qZB2qz) G1Aޚ:AIޚ:IQ:! :YW ;YRYWYRYai}6!q*;qޚ:qq qY>^0;qq}6!Yq:;q1q1Y1 q@;)F;yޚ:yyy #y@;7t;Jz;Y]-- l 3'^i9 G83'Y;Y;Y;Y ;^Y;Y5;YI;Ya;i9 G8!;!;!l!l!l!;;!;!;;< L<9B|X ai=ii=i$i=i/o=$g @=m^mYf^YOi75qq q==[3g) /L= A f $=5> F >S>,<& O>I >$>.>)7>xRI Hu!b>>}>^ %4D>T>p>:izc?Yj?p?$?7j)G)o?4??)???q ??0U!Ͳ0n9?h/IU >?II IzS S@ i!|ou4&1@<^c A@D^U@ ^[@ !_ !o4iM ^s<111VA1Q]AQEAAQiQ  !iAiAQ6QB\d`\^\9%lG8ld\إ\9%tG8td\إd9%|G8A RB|ddإd^i| ^ qi B B BYx#I B1BYBY Y B{QC Z{XCY#x+/GWɭ_C@fCYgC7CJC!CA0!r)gC)~CACICyCCy)CqCq)CYCYWYRYWYR44^aI|WD|W|Wi}aM AAADS y %DI,DQ (9  #DD 0DDDXDR2 ]\D eoaD mDoxDo ooDoDoD láD DYDYD Dy D*DE-E E9E9%G8 }aZ&d[^EfjEQ oE!jE!z4E9 ;, I I  "AA[EEE¼ES x'|x'=FNF h!F0S .F,J,,A DF! Y)kFQ99 wF))FB2Y7F)GPE)XFQKQ#!YFAlF11mAvFIQYIG)P)d)di v)"P).P1 9G);x!MumqqqGq{!q ^Gi!o|G)))))EI1 1 Gg^11 17U1 \U1K1X1^ eU1w  "  )1j 9@HHHyNHyv3+iԸ09 8+aHHa`aa aaa%aA9)^H)]dH)mp,  x 9 h):))I*Y:Y) 01HiIIITQQ"Q҄Q!1 o'I-Iq }2iKI1oQIeIQ (lIlIlIlI!IUqu.q8qCq1 B>aUQ b((9 (ŔfJyxJyAJ J7JyX\`dtx|$(`d h l      = B = B  X\`h= lB p HbL    LPTX5\<@DHLP .cK.kK.s.[{&.#J.3J.;J.CJ.KJ.S"K.KGK+{&K'3+I+{&i+{& 4 # 5#s+$T7+$T7 +$T7I+$T7i+$T7e$$8G8+ $@%`>%y%%%&+$eFH[8eF ;I$$9%n&&&&&'9'F'^''(((()\)k))))))H*N**** +)+D+_+~+++++-,:,@,N,,,,,,- ---'-A-J-U-------..".2.L.X.`.e.k.~......//9/D/U/[/d///////////0!020:0l0s0z0000000 1181b111222H2Z2e222223!3*32383L3V3`3n3s333333334 44.4<4R44444444o555F666666 77%7>7K7Z7g7777777778P8f8m8v8888899-9R99::0:Z::::::::;;M;k;;;;;<=======>X>>>>>?w?????@@@*@b@k@@@@@@;AJAiAAAABjBBBBBBBC CCC$C-C3CFLF_FFPGVGiGrGyGGGGGH(H3H9HUHkHqHHH!I3IYIqIIII-J3J[J`J%).47 ? d h ilu{}e)))%./4_7>FFM^M^M^M^MjMjMkMNkMkMkMk%l\wM2|q2|q^M    !"%!&$(*),,1/:1=2>3A4B6H7J9Q:T;V?XBhEiFjOnPoQrSsWu^v`}abehijmnpqsuwx{}~t?INI!0bt  0'>'F'S''(O()"$)"S),,*,--..///k1s1{1111>3F3455'5:567 777*71J77u(78s8JM1i M'@Mo Mo Mo MNNu "N4NGNRN!@IZPZPTTTU- <oWW s8=MY[,]% ]]"]. .*]]]^j ^u '^ ```t aau au bZeeff#f5fGf\fnfffffg hffi ffi`jTg,u6u>uHuWu% v_vBmvBg |l|||}}T~\~:]1u NYdu Łu #/u (J2]G`j†Άۆ Lnu JŊΊߊu  7t$1u )u 0?K*(ጮ 7jviɏ׏/DWk~’ܒ+K^q9:;?@   A B Q R D C tsEF G"!H^]JI|}gjiv  !!""#$$%%& &'!("()$*#*+&,%,-(.'./0012233x4w455667799;;==??AACC EEGGIIKK!M M#O"O%Q$Q'S&S9U:WFYG[J]K_Labccedgeifkgmhoiqjsvuxwwwyy~{}'()+,./<=>?A@BCEDFGIHKJLMNOPQRSTUVWXYjk34TUWVYX[Z\]^_`adcefhijlkn    !#%')+-/13355779;=?A C)E*G,I+I-K2M3OQQSUWWYY[[]]__aacceeggii.k-k2m3maobojqiqlsks{uzu}w|wyy{{}  #$&%(*+,-/.0123546789:;<=?>ABCDEFGHIJKLMNOPQRSTU*+7H7JL ȪӪ!Zb/=*w^kt| ']ku ""o"$$&&'"'') ***+1,a-x--%/\0[1Q2z355A5555566u77788@8888889$9999':J:;;;;<<<<<<?:@L@@@AAABB>EGEGH35 79;;F=R8 8@8';Q@8   ) 5 A O \ i z 8   0 /  ZQ7 xã2k ,n Wp v  54648797:7;7<7=7>7@?CBDBGFHFIFJFKFLFVU_^CCCDUXn;-.(/-/0 011(/>>!AcWindows.dllMenuServicesAutodesk.AutoCAD.Internal.WindowsupdateRecentDocumentsDelegateSHFILEINFONativeMethodsAppMenuUtilitiesSearchContentloadTabContentsDelegatepostProcessResultsDelegateMatchTypeKeywordRecordRelativeMatchTypeSearchRecordsSearchResultSearchUtilMacroResultItemBindingTargetForToggleButtonHelpButtonServicesQuickAccessToolbarServicepostRevertCollectionChangeDelegateWorkspaceQuickAccessToolbarDictionaryQATItemCollectionAutodesk.AutoCAD.WindowsCommandsAutodesk.AutoCAD.RibbonQuickPropertiesFrameEventArgsQuickPropertiesFrameIRibbonComboBoxTextChangeColorControlColorItemColorComboItemCollectionAcadColorConverterTextChangeNotifyComboBoxEditStateEditStateChangedEventArgsRenamedEventArgsRenamedEventHandlerEditStateChangedEventHandlerNameTextBoxSpinnerAcInfoCenterConnAutodesk.AutoCAD.AcInfoCenterConnInfoCenterManagerCommCntrAcConCUIRibbonMigrationBalloonMyAutoCADBalloonInfoBalloonEventArgsShowInfoBalloonDelegateInfoBalloonManagerResourcesAutodesk.AutoCAD.Windows.PropertiesQuickViewDataManagerLayoutsQuickViewDataManagerQuickViewManagerLayoutsQuickViewManagerQuickViewLevelActiveIndexChangedEventHandlerActiveIndexChangedArgsQuickViewControlTaskSourcePerformTaskEventArgsRenameTaskEventArgsDisplayChangedEventArgsGetListBoxDataPerformTaskEventHandlerDisplayChangedEventHandlerQuickViewDataActiveChangedEventHandlerQuickViewDefaultDataProviderQuickViewDocumentsControlQVCommandPerformQVCommandQuickViewLayoutsControlShowMotionViewsControlLoopStatusChangeStopPlayBackAllPlayBackShowMotionCloseRenameErrorChoiceYesOrNoChoiceUtilQuickViewLayoutUpdateStateQuickViewLayoutEventsListenerQuickViewDocumentDataDocumentsQuickViewDataManagerQuickViewFrameDocumentsQuickViewManagerDefaultImageTypeQuickViewManagerUtilityChoiceSliderItemToSliderControlConverterNav3DLensLengthConverterNav3DFOVConverterNav3DStepSizeConverterLightsMidTonesConverterLightsDateConverterLightsTimeConverterRuleTriggerConditionAssemblyReferenceTabSelectorRulesITabEvaluatorTabEvaluatorFactoryStatusBarPanesCheckListOpenDrawingsListQuickAccessUndoControlQuickAccessRedoControlUndoRedoHandlerRibbonCommandButtonRibbonHwndControlRibbonDataBoundDropDownDialogLauncherRibbonContentRibbonWorkspaceResolveContentRibbonTabDataResolveReferencesDataDocumentReactorCommandEventReactorICommandEventTargetRibbonPaletteSetAcadHostEventTypeAcadHostEventArgsContextualTabEventArgsExtensionMethodRibbonSelectionManagerRibbonServicesRibbonUtilTripleFindTextBridgeDimensionCollectionViewSourceNullToBooleanConverterTextStyleImageConverterVisualStyleImageConverterCommandDrivenValueToBooleanConverterPaletteToggleButtonConverterSystemVariableToggleButtonConverterSystemVariableNegativeToggleButtonConverterXRayModeToggleButtonConverterDrawingStatusBarToggleButtonConverterVisualStyleSilouetteEdgesToggleButtonConverterVisualStyleEdgeJitterToggleButtonConverterValueToAbsoluteValueConverterPositiveSystemVariableToIsEnableConverterPositiveAndNotZeroSystemVariableToIsEnableConverterNonZeroSystemVariableToBooleanConverterMultiValueToBooleanConverterVisualStyleEdgeOverhangToggleButtonConverterSunStatusToggleButtonConverterLineTypeImageConverterLineWeightImageConverterColorImageConverterSystemVariableToRibbonCommandButtonConverterUcsIconVariableToRibbonCommandButtonConverterCellLockedStyleCellStateToCellLockedStyleConverterFilterItemFilterableCollectionAddNewColorConverterRibbonFormattedSpinnerLockUIToBooleanConverterPoint3dDoubleToStringConverterGreaterThanOneBooleanConverterEqualToOneBooleanConverterLockedObjectsCheckerFrozenOffLayerObjectCheckerDataItemCollectionViewSourceCellRangeToCanMergeConverterCellRangeToCanUnmergeConverterCellRangeToCanDataLinkConverterCellRangeToCanManageContentConverterDataItemToCommandConverterColorToCommandConverterBindableStandardConverterAcFocusConverterLayerValidatorPriorityBindingWorkaroundRibbonTextBoxItemShowMotionDataManagerISMManagerShowMotionManagerHideableDialogSettingsDialogAcadToolTipToolTipHelpServiceToolTipContentSourceToolTipUtilCommandToolTipSettingResxResourceModuleComponentHostServiceRibbonCommandHandlerHelpInformationSettingsContextHelpToolTipPropertyTypePropertyToolTipPropertyPropertyCollectionColorSymbolRolloverColorConverterRolloverColorLineWeightSymbolNameDescriptionToolTipWin32POINTRECTEnumWindowProcWndProcGeneratedInternalTypeHelperXamlGeneratedNamespacemscorlibSystemObjectMulticastDelegateValueTypeAdWindowsAutodesk.Internal.WindowsISearchableEnumAutodesk.WindowsRibbonCommandItemWindowsBaseSystem.WindowsDependencyObjectSystem.Collections.GenericDictionary`2AcCuiAutodesk.AutoCAD.CustomizationWorkspaceQuickAccessToolbarRibbonItemCollectionEventArgsFloatingFramePresentationFrameworkSystem.Windows.ControlsComboBoxSystem.Collections.ObjectModelObservableCollection`1System.Windows.DataIValueConverterTextBoxControlacdbmgdAutodesk.AutoCAD.RuntimeIExtensionApplicationIDisposableAutodesk.Internal.InfoCenterICommunicationCenterConnectorStackPanelSystem.Windows.MarkupIComponentConnectorGridIStyleConnectorPresentationCoreSystem.Windows.Media.AnimationAnimatableWindowRibbonChecklistButtonSystem.Windows.InputICommandRibbonMenuButtonAutodesk.Windows.ToolBarsQuickAccessUndoButtonQuickAccessRedoButtonRibbonButtonRibbonHwndRibbonSplitButtonacmgdPaletteSetIRibbonControlHostWindowHostEventArgsSystem.ComponentModelINotifyPropertyChangedCollectionViewSourceIMultiValueConverterRibbonSpinnerRibbonItemIComponentHostServiceSystem.ConfigurationApplicationSettingsBaseTypeConverterInternalTypeHelperSystem.Windows.ThreadingDispatchermMainDispatcherSystem.ThreadingThreadmFillRecentDocThreadInitializeApplication_BeginQuitAutodesk.AutoCAD.ApplicationServicesProfileEventArgsUserConfigurationManager_CurrentProfileChangedUserConfigurationManager_CurrentProfileChangingAutodesk.AutoCAD.Internal.ReactorsCuiLoadEventArgsCuiEventManager_LoadRibbonSetSearchResultTemplateSetSearchContentsList`1RibbonMenuMacroLoadMenuMacrosLoadMenuContentFillOpenDocumentsFillRecentDocumentsUpdateRecentDocumentsFillRemoteDocumentsDocumentCollectionEventArgsDocumentManager_DocumentActivatedDocumentManager_DocumentToBeDestroyedApplicationMenu_ClosingApplicationMenu_OpeningLoadAppMenuSettingsSaveAppMenuSettingsmMacrosMenuContentmMenuContentmDefaultMenuContentmbIsZeroDocmProductNamemMaxRecentFiles.ctorInvokeIAsyncResultAsyncCallbackBeginInvokeEndInvokehIconiIcondwAttributesszDisplayNameszTypeNameDestroyIconLoadLibraryFreeLibrarySystem.TextStringBuilderLoadStringExtractIconExtractIconExSystem.Windows.MediaImageSourcemFileImagesRecentDocumentFindRecentDocumentGetFileImageConvertIconToImageSourceParseResourceStringMicrosoft.Win32RegistryKeyGetAppMenuKeyApplicationMenuItemFindMenuItemFindMenuItemIndexLoadThirdPartyMenuItemsCreateThirdPartyMenuItemQuickAccessToolBarSourcemQatSourceRibbonTabCollectionmTabsRibbonTabmVisibleTabsISearchResultsSearchSearchInQATSearchInAppMenuSearchInRibbonSearchInMacrosLoadTabContentsForSearchPostProcessSearchResultsvalue__BestMatchNormalMatchRelativeMatchNonemKeywordget_KeywordmbFoundget_IsFoundset_IsFoundKeywordIsFoundInTooltipInTagInCommandClonemSearchTextget_SearchTextmKeysget_KeysmRelativeMatchTypeget_RelativeMatchTypeset_RelativeMatchTypemMatchTypeget_MatchTypeset_MatchTypeSearchTextKeysget_FoundInCommandget_FoundInTagget_FoundInTooltipget_IsCheckedBindingTargetset_IsCheckedBindingTargetmIsCheckedBindingTargetFoundInCommandFoundInTagFoundInTooltipIsCheckedBindingTargetConvertSearchStringToRecordsRemoveAllInvalidSearchKeysIsOnlyContainSpecialSearchSymbolFormatSearchResultPathTranslateToRegularExpressionSearchKeywordExistsContainAnyKeywordInTextAllKeywordFoundSearchTextFromItemSearchTextFromTitleSearchTextFromMacroContainAnyKeywordInCommandContainAnyKeywordInTagContainAnyKeywordInTooltipSearchRibbonItemSearchItemsSearchCommandItemSearchMacroSearchNamedItemCreateSearchResultCreateNamedSearchResultCreateSearchResultForPanelCreateSearchResultForMacroRemoveEscapeExtractCLICommandmMacroget_MacroMacroDependencyPropertyIsCheckedProperty.cctorget_IsCheckedset_IsCheckedIsCheckedLoadHelpButtonGetHelpButtonKeyOnApplicationIdleLoadQuickAccessToolbarEnableQuickAccessToolbarIsDefaultItemget_ToolbarSourceRestoreZeroDocItemsRestoreItemsInitQATMenusClearToolbarLoadContentMenuGroupDataLoadQuickAccessToolbarContentApplyWorkspaceCreateToolbarItemsAddPropertyChangedHandlerGetMenuGroupDataCustomizationSectionCreateToolbarDefinitionSaveToolbarDefinitionQuickAccessToolbarDataLoadQuickAccessToolbarDataSaveQuickAccessToolbarDataCollection`1QuickAccessToolbarGetVisibleElementsGetToolbarElementSystem.Collections.SpecializedNotifyCollectionChangedActionCreateQuickAccessToolbarElementWorkspaceSaveWorkspaceQuickAccessToolbarSaveCurrentQuickAccessToolbarItemsSaveQuickAccessToolbarElementDisplayTaskDialogsPropertyChangedEventArgsStandardItem_PropertyChangedQuickAccessToolbarService_PropertyChangedCuiEventManager_CUILoadedAddAllStandardItemsWorkspaceEventArgsCuiEventManager_WorkspaceRestoreCuiEventManager_WorkspaceRibbonSaveAcadApplication_IdleAcadApplication_BeginQuitAcadApplication_BeginCustomizationModeAcadApplication_EndCustomizationModeNotifyCollectionChangedEventArgsQuickAccessToolbar_CollectionChangedRibbonServices_RibbonPaletteSetCreatedPaletteSetStateEventArgsRibbonPaletteSet_StateChangedget_Serviceget_IgnoreChangeset_IgnoreChangeget_HasCustomizeCommandQuickAccessToolBarLocationQuickAccessToolbarOrientationGetToolbarOrientationmQuickAccessToolbarServicemItemsmZeroDocItemsmWorkspacesmQuickAccessToolbarItemsmStandardItemsmbIgnoreChangembRestoreDocStatemsCurrentToolbarmsXmlDatambHasCustomizeCommandmLocationmbUpdateToolbarLocationToolbarSourceServiceIgnoreChangeHasCustomizeCommandMergeAndOverwriteCleanUpget_Orderingset_Orderingk__BackingFieldOrderingRibbonPlusRibbonRibbonCloseQVDrawingQVDrawingCloseQVLayoutQVLayoutCloseNAVSMOTIONNAVSMOTIONCLOSEDoCloseNavMotionget_IsQuickViewManagerActiveget_QuickViewManagermQuickViewManagerSystem.ResourcesResourceManagerresourceManget_ResourceManagerget_PlusRibbonPromptget_Error_Specified_Tab_Cannot_Be_FoundIsQuickViewManagerActivePlusRibbonPromptError_Specified_Tab_Cannot_Be_Foundget_IdmIdIdEventHandler`1ButtonClickedadd_ButtonClickedremove_ButtonClickedExpandedadd_Expandedremove_ExpandedCollapsedadd_Collapsedremove_CollapsedFrameworkElementOnFrameButtonCommandExpandContractOnTextChangedSelectedColorPropertyDependencyPropertyChangedEventArgsOnSelectedColorChangedget_ColorItemsset_ColorItemsAutodesk.AutoCAD.ColorsColorget_SelectedColorset_SelectedColorAddMRUColorFindColorLoadColorLoadSelectColorItemLoadPredefinedColorsReloadColorsSelectColorItemSelectionChangedEventArgsColorCombo_SelectionChangedDocumentCreatedDocumentBecameCurrentDocumentActivatedmPreloadedColorsmByBlockColorIndexmByLayerColorIndexmSelectColorTagmNoneColorIndexmColorItemsColorItemsSelectedColorColorPropertyToStringget_Colorset_Colorget_DisplayNameset_DisplayNamemDisplayNameDisplayNameTypeSystem.GlobalizationCultureInfoConvertConvertBackGetWPFColorFromAcadColorget_IsNotifingTextChangeset_IsNotifingTextChangeKeyEventArgsOnKeyDownOnIsKeyboardFocusWithinChangedGetIRibbonComboTextChangeNotifyTextChangedmIsNotifingTextChangeIsNotifingTextChangeReadReadWriteset_Stateget_StatemStateStateset_OldNameget_OldNameset_NewNameget_NewNamemOldNamemNewNameOldNameNewNameEditStateChangedadd_EditStateChangedremove_EditStateChangedmActualTextPropertyget_ActualTextset_ActualTextmIsEditablePropertyget_IsEditableset_IsEditableBrusholdBrushActivateDeactivateCalculateDisplayTextOnApplyTemplateMouseButtonEventArgsOnMouseDoubleClickUpdateRoutedEventArgsOnLostFocusOnPropertyChangedget_SameNameset_SameNameRenamedadd_Renamedremove_RenamedmTextBeforEditmRenameTextmbSameNameActualTextIsEditableSameNameOnCoerceValueMaximumPropertyMinimumPropertyIncrementPropertyValuePropertyTextPropertyImagePropertySetTextset_Maximumget_Maximumset_Minimumget_Minimumset_Incrementget_Incrementset_Valueget_Valueset_Textget_Textset_Imageget_ImageOnUpButtonClickedOnDownButtonClickedOnPreviewKeyDownmTextBoxSystem.Windows.Controls.PrimitivesRepeatButtonmUpButtonmDownButtonMaximumMinimumIncrementValueTextImagemICMTerminateNeedInfoCenterOnSendFeedbackPaletteMgrmInfoCenterProductProfilemProdProfileDispatcherTimermFlushBalloonQueueTimermCommCntrConnInfoToolbarmToolbarmTempRolloutActiveFlushBalloonQueueCurrProfileChangedInitToolbarInfoToolbarItemClickedEventArgsToolbarButtonClickedget_Toolbarget_PaletteManagerToolbarFocusChangedToolbarMovedToolbarResizeToShowInfoBalloonHandlerConvertMessageToXamlDisposeToolbarPaletteManagerGetRegProdRootKeyGetProdProfileReadPropertyOnCurrentProfileChangedGetProductProfileget_ProductRootKeyget_SubAwareClientInfoLaunchSubAwareModuleCurrentUICultureget_CurrentProfileKeyget_SubAwareServiceUrlget_SearchServiceUrlEnableProfileBasedInfoCenterIcQueryHandlerIcLaunchEventArgsIcLaunchHandlerHelpEventArgsInvokeHelpCurrentProfileChangedadd_CurrentProfileChangedremove_CurrentProfileChangedProductRootKeySubAwareClientInfoCurrentProfileKeySubAwareServiceUrlSearchServiceUrlOnClickHyperLinkShowInfoBalloonTextBlockm_detailTextSystem.Windows.DocumentsHyperlinkm_theHyperLink_contentLoadedInitializeComponentSystem.Windows.Markup.IComponentConnector.ConnectConnectSetHyperLinkUriget_MessageIDget_AppNameget_Titleget_MainMessageget_DetailMessageget_XamlFragmentget_UseXamlget_ImageSourcemMessageIdmAppNamemTitlemMainMessagemDetailMessagemXamlFragmentmImagemImageSourcemUseXamlMessageIDAppNameTitleMainMessageDetailMessageXamlFragmentUseXamlmInstanceGetManagerFlushQueueOnShowInfoBalloonadd_OnShowInfoBalloonremove_OnShowInfoBalloonQueue`1mQueueresourceCultureget_Cultureset_CultureSystem.DrawingBitmapget_PlayMaskImageCulturePlayMaskImageFreeDataOnIdleget_LayoutDataListRefreshLayoutDatamLayoutDataListmLayoutsQuickViewManagerLayoutDataListSetFocusEnableWindowUpdateQVPinButtonStateget_QVFrameget_UpdateDataset_UpdateDataget_UpdateMarginset_UpdateMarginInvokeQVCtrlQuickViewFrame_SourceInitializedQuickViewFrame_KeyDownCloseQVCtrlSystemVariableChangedEventArgsAcadApplication_SystemVariableChangedQuickViewFrame_ClosedUpdateQuickViewUICancelEventArgsQuickViewFrame_ClosingDocumentDestroyedEventArgsDocCollection_DocumentDestroyedMouseEventArgsQuickViewFrame_MouseLeaveEnableQVFrameQuickViewFrame_MouseEnterQuickViewFrame_DeactivatedAddAcadEventHandlersAutodesk.AutoCAD.PlottingServicesEndPlotEventArgsPlotReactorManager_EndPlotBeginPlotEventArgsPlotReactorManager_BeginPlotRemoveAcadEventHandlersAcadApplication_LeaveModalAcadApplication_EnterModalApplicationEventManager_ApplicationMainWindowMovedSizedAcadResponseTimer_TickCloseHiddenQVWindowSystemEvents_DisplaySettingsChangedmQVFramemQVDataMgrmUpdateDatamUpdateMarginSystem.Windows.InteropWindowInteropHelpermWihPlotReactorManagermPlotReactorManagermAcadResponseTimermMaxLevelQVFrameUpdateDataUpdateMarginget_GettingListBoxDataset_GettingListBoxDataGetInstanceQuickViewLayoutsControl_PerformTaskUpdatePopupStyleAddAdditionalAcadEventHandlersRemoveAdditionalAcadEventHandlersDocCollection_DocumentActivatedLayoutTaskmSelfmGettingListBoxDatamUpdateLayoutmRegenAllmEventsListenerGettingListBoxDatamImageHeightPropertyget_ImageHeightset_ImageHeightmScrollOffsetPropertyget_ScrollOffsetset_ScrollOffsetget_Levelset_Levelget_Activeset_ActivemActiveIndexPropertyget_ActiveIndexset_ActiveIndexget_FinalMarginset_FinalMarginActiveIndexChangedadd_ActiveIndexChangedremove_ActiveIndexChangedListBoxGetListBoxGetTopParentDurationBeginWidthAnimationWidthAnimation_CompletedBeginMarginAnimationMarginAnimation_CompletedmLevelmActivemOldIndexmFinalMarginmFinalWidthmTopParentDoubleAnimationmDAXLastThicknessAnimationmTAXLastImageHeightScrollOffsetLevelActiveActiveIndexFinalMarginmNewget_NewmOldget_OldNewOldMAX_LEVELmnMinSize1mnMinSize2mMilliSecondsPerPixelGetSystemMetricsGetQuickViewControlMaximumHeightget_QVDataDefaultListSetToolTipPinButtonget_IsPinnedset_IsPinnedget_IsContextMenuVisibleset_IsContextMenuVisibleget_IsEditModeget_AnimationONUpdateTextget_Idleset_Idleget_nMouseWheelCustomiseUIInitScreenBoundsGetActiveImageTextBoxUpdateAllActiveLevelPreviewsListBoxItem_LoadedListBoxItem_MouseRightButtonUpRightIcon_ClickLeftIcon_ClickImage_MouseDownActivatePreviewListBoxItemGetLbiFromNameTextBoxBorderButtonGetLbiBorderFromIconButtonsActivateListBoxItemNameTextBox_RenamedNameTextBox_MouseDoubleClickGetImageBigSizeGetAnimationDurationCreateChildLevelListBoxItem_MouseMoveListBoxItem_MouseEnterQuickViewDisplayChangedMouseWheelEventArgsQuickViewLevel_PreviewMouseWheelFindNameInListBoxControlTemplateTypeofNameFindNameInListBoxDataTemplateGetListBoxItemFromImageBorderGetListBoxItemWidthQuickViewLevel_MouseEnterQuickViewLevel_MouseMoveShowChildLevelForActiveLBIShowChildLevelHideChildLevelQuickViewLevel_MouseLeaveStopAutoScrollingStartAutoScrollingShowScrollArrowsHideScrollArrowsGetArrowGetControlPanelLeftEdgeGetLevelXMarginQuickViewCtrl_LoadedQuickViewLevel_ActiveIndexChangedAddControlPanelHolderControlPanelHolder_LoadedAddControlPanelUIElementGetControlPanelFindLevelIndexCreateLevelQuickViewLevel_PreviewKeyDownScrollRightScrollLeftMoveToLevelItemHighlightListBoxItemUnHighlightListBoxItemIsCtrlKeyPressedControl_KeyDownNameTextBox_EditStateChangedScrollChangedEventArgsScrollViewer_ScrollChangedUpdatePinStatemQVPinButtonPerformTaskadd_PerformTaskremove_PerformTaskDisplayChangedadd_DisplayChangedremove_DisplayChangedmActiveLBImActiveParentLBImnLevelTotalmLevelArraymRootPanelmDefaultLevelmDefaultLevelIndexmControlPanelHoldermXScreenLeftmXScreenRightmIsPinnedmbAllActiveLevelPreviewsSelectedmIsEditModemIdlemIsContextMenuVisiblemAnimationONmKeyBoardNavigationmControlLoadedmQVDataDefaultListmGetListBoxDatamnMouseWheelmAutoScrollOnmScrollLevelmScrollListBoxScrollViewermScrollScrollViewermiScrollLevelmScrollLeftButtonmScrollRightButtonmLevelChangedPointmLastMousePointQuickViewCtrlSystem.Windows.Markup.IStyleConnector.ConnectQVDataDefaultListIsPinnedIsContextMenuVisibleIsEditModeAnimationONIdlenMouseWheelLeftIconRightIconThumbnailTextLabelmTaskSourceget_TaskSourcemIndexget_IndexIndexmPreviousLevelmCurrentLevelget_PreviousLevelget_CurrentLevelPreviousLevelCurrentLevelmHasChildPropertyget_HasChildset_HasChildmImagePropertySystem.Windows.Media.ImagingBitmapSourcemImageToolTipPropertyget_ImageToolTipset_ImageToolTipmLeftButtonImagePropertyBitmapImageget_LeftButtonImageset_LeftButtonImagemRightButtonImagePropertyget_RightButtonImageset_RightButtonImagemFileTypeIconPropertyget_FileTypeIconset_FileTypeIconmImageNamePropertyget_ImageNameset_ImageNamemIsImageNameEditablePropertyget_IsImageNameEditableset_IsImageNameEditablemCustomDataPropertyget_CustomDataset_CustomDatamLeftButtonToolTipPropertyget_LeftButtonToolTipset_LeftButtonToolTipmRightButtonToolTipPropertyget_RightButtonToolTipset_RightButtonToolTipmImageWidthPropertyget_ImageWidthset_ImageWidthmTextBoxMaxWidthPropertyget_TextBoxMaxWidthset_TextBoxMaxWidthFreezableCreateInstanceCoreActiveChangedadd_ActiveChangedremove_ActiveChangedHasChildImageToolTipLeftButtonImageRightButtonImageFileTypeIconImageNameIsImageNameEditableCustomDataLeftButtonToolTipRightButtonToolTipImageWidthTextBoxMaxWidthmQVCtrlSetUIControlGetQvDataListget_InvokedExternalUIset_InvokedExternalUIAutodesk.AutoCAD.InternalLayoutContextMenuCommandLayoutContextMenuHandlerDocumentsContextMenuGetActiveFileNameArrangeIcons_ClickTileVertically_ClickTileHorizontally_ClickCascade_ClickCopyFilesasaLink_ClickCloseAll_ClickCloseOtherFiles_ClickSaveAll_ClickCloseFILENAME_ClickCallCommandQVNewDrawingButton_ClickQVOpenDrawingButton_ClickQVPinButton_ClickQVCloseButton_ClickmPerformQVCommandmInvokedExternalUIInvokedExternalUIWindowsArrangeIconsWindowsTileVerticallyWindowsTileHorizontallyWindowsCascadeCopyFileAsALinkCloseAllCloseOtherFilesSaveAllCloseFilePublishLayoutButton_ClickNewLayoutButton_ClickIDS_OPEN_READ_ONLYGetDoubleClickTimeisOEMReadOnlyCustomizeContextMenuNewView_ClickedUpdateThisView_ClickedUpdateThisCategory_ClickedUpdateAll_ClickedMoveLeft_Clicked_ShotMoveLeft_Clicked_SeqMoveRight_Clicked_ShotMoveRight_Clicked_SeqRename_ClickedDelete_Clicked_ShotDelete_Clicked_SeqProperties_ClickedDoubleClickTimer_TickContextMenuEventArgsControlPanel_ContextMenuOpeningShowTaskDialogsmPlayButton_ClicksmStopButton_ClicksmLoopButton_ClicksmNewViewButton_ClickUpdateQuickViewPlayStatusUpdateLoopButtonStatusGetPlayMaskImageget_ActiveListBoxNameset_ActiveListBoxNameget_ActiveCategoryNameset_ActiveCategoryNameget_NodeIndexArrayset_NodeIndexArrayget_PauseAllPlayset_PauseAllPlaymActiveListBoxNamemActiveCategoryNamemContextMenuListBoxNamemContextMenuLevelmLoopStatusChangemStopPlayBackmAllPlayBackmShowMotionClosembPauseAllPlaybtnPlaybtnLoopmPlayMaskImagemDoubleClickTimermDoubleClickActiveListBoxNameActiveCategoryNameNodeIndexArrayPauseAllPlaySpecifyNewNameRemainOldNameYesNoFindVisualChildchildItemResourceDictionaryRoutedEventHandlerAddButtonMenuItemAddChildToMenuContextMenuAddChildtoContextMenuDocumentRunCommandCIPClickedLogCIPScrollModeLogeNotModifiedeLayoutModifiedeLayoutDictionaryModifiedResetStateAutodesk.AutoCAD.DatabaseServicesDatabaseSubscribeLayoutEventsUnsubscribeLayoutEventsDbEvents_ObjectModifiedDbEvents_DictionaryModifiedDictionaryEventManagermDbEventsmDbmnLayoutsget_DocumentModifiedget_UpdateStateSubscribeAcadEventsUnsubscribeAcadEventsRefreshImageDatabaseIOEventArgsDatabase_SaveCompleteDocumentModifiedUpdateStateDataUpdateTimer_TickClearDocumentDataListRemoveDocumentGetCurrentDocumentAddQVDataForDocImageskDefaultPreviewSizemCurrentDocDatamDocumentDataListmDocumentsQuickViewManagermDataUpdateTimermUpdateRequestByTimerUpdateQuickViewPlacementmWindowBorderThicknessget_UpdateLayoutDataset_UpdateLayoutDataQuickViewDocumentsControl_DisplayChangedQuickViewDocumentsControl_PerformTaskDocCollection_DocumentCreatedDocumentTaskmUpdateLayoutDataUpdateLayoutDataeXSymboleModeleLayoutGetFileNameWithoutExtensionGetDocumentCIPQVLayoutOpenedStateLogSaveDocumentCloseAllDocumentsSaveAllDocumentsCloseDocumentActivateDocumentPublishPlotActivateLayoutClearCommandEditorIsValidLayoutNameRenameLayoutFindQuickViewDataGetDefaultImageCreateBitmapSourceFromBitmapUpdateQVDataForLayoutImagesLayoutThumbnailEnumeratorGetLayoutCountAddQVDataForLayoutsAddQVDataForLayoutImagesQuickViewData_ActiveChangedShowMessageCancelConvertToSliderValueConvertFromSliderValueConvertToTextConvertFromTextget_FormatStringset_FormatStringmsFormatStringFormatStringTryParseLensLengthToFOVFOVToLensLengthget_Tabsset_Tabsget_Contentset_Contentget_Uidset_Uidget_Triggerset_Triggerget_Activateset_Activateget_Themeset_Themek__BackingFieldk__BackingFieldk__BackingFieldk__BackingFieldk__BackingFieldk__BackingFieldk__BackingFieldTabsContentUidTriggerThemeSelectionSystemVariableget_Namespaceset_Namespaceget_Assemblyset_Assemblyk__BackingFieldk__BackingFieldNamespaceAssemblym_refsget_Referencesget_Rulesset_Rulesk__BackingFieldReferencesRulesICollection`1EvaluateIEnumerable`1LoadGenerateRuleGenerateInitializerConsolidateCompileStatusBarPanesCheckList_OpenedItemCollectionAddListItem_CheckStateChangedExecuteMenuCommandCanExecuteEventHandlerCanExecuteChangedadd_CanExecuteChangedremove_CanExecuteChangedOnCanExecuteChangedExecuteExecutedRoutedEventArgsOnCurrentDrawingCommandCanExecuteRoutedEventArgsMenuItemCanExecuteRoutedCommandget_CurrentDrawingOpenDrawingsList_OpenedOpenDrawingsList_ClosedUpdateItemCurrentDrawingCommandCurrentDrawingQuickAccessUndoControl_InitializedQuickAccessRedoControl_InitializedToolBarHistoryButtonmHistoryButton_DropDownOpeningget_IsUndoget_IsEnabledUpdateHistorymHistoryButtonmbUndoIsUndoIsEnabledset_Macroget_MenuMacroIdset_MenuMacroIdget_SystemVariableValueset_SystemVariableValueCopyFromOnInitializedget_UserDataGetHashCodeEqualsmMenuMacromMenuMacroIdmSystemVariableValueMenuMacroIdSystemVariableValueUserDatamControlNameget_ControlNameset_ControlNamemModuleget_Moduleset_ModuleSystem.Runtime.InteropServicesHandleRefBuildWindowCoreSizeGetWindowSizeDestroyWindowCoreControlNamemCommandHandlerget_ContextualTabEvaluatorIsCommandEnabledSystem.CollectionsIListCollapseSeparatorsSubsetSubsetCollectionget_ZeroDocQATget_NonZeroDocQATget_ZeroDocAppMenuget_NonZeroDocAppMenuget_ZeroDocHelpButtonget_NonZeroDocHelpButtonget_AppFrameResourcesget_UnreadControlResourceFilesLoadControlResourceIsListableGetAllRibbonControlsWorkerGetAllRibbonControlsTryGetRibbonControlGetRibbonControlGetNonZeroDocumentQATControlMenuGroupTypeEnumget_MenuGroupNameget_FileNameget_MenuMacrosRibbonTabSourceget_TabElementsGetTabGetTabElementRibbonPanelSourceGetRibbonPanelElementRibbonRootFindItemResolveCreateRibbonPanelSourceMenuMacroCreateRibbonCommandButtonsmTabElementsmPanelElementsmTypemsMenuGroupNamemsFileNamemMenuMacrosmRibbonControlsmAppFrameResourcesmContextualTabEvaluatormUnreadControlResourceFilesContextualTabEvaluatorZeroDocQATNonZeroDocQATZeroDocAppMenuNonZeroDocAppMenuZeroDocHelpButtonNonZeroDocHelpButtonAppFrameResourcesUnreadControlResourceFilesMenuGroupNameFileNameMenuMacrosTabElementsWSRibbonRootset_WorkspaceRibbonRootget_WorkspaceRibbonRootResolveWorkspaceRibbonControlSaveWorkspaceGetToolPaletteGroupSetToolPalettGroupWSRibbonTabSourceReferenceGetWorkspaceReferencemWorkspaceRootWorkspaceRibbonRootFindMenuMacroSetRibbonCommandButtonComponentManager_ToolTipOpenedRibbonItemEventArgsComponentManager_ItemInitializedCommandToolTipDataSetToolTipDataRibbonToggleButtonRibbonGalleryControlRibbonRowPanelRibbonSeparatorRibbonControlBaseget_Tabset_Tabset_MenuGroupNamemTabTabget_CUIMenuMacrosget_PreviewmCUIMenuMacrosmRibbonMenuMacrosmbPreviewCUIMenuMacrosPreviewDocumentManager_DocumentBecameCurrentDBObjectIsActiveDocumentObjectAddDocumentEventsRemoveDocumentEventsAddEventsRemoveEventsmbDocumentEventsPlantedget_InstanceRemoveCommandEventArgsDocument_CommandWillStartDocument_CommandEndedDocument_CommandCancelledDocument_CommandFailedmReactormReactorTargetsmDocumentsInstanceCommandWillStartCommandEndedCommandCancelledCommandFailedmnDefaultPaletteSetStylekMenuItemNoneLoadedadd_Loadedremove_LoadedUnloadingadd_Unloadingremove_UnloadingVisibleChangedadd_VisibleChangedremove_VisibleChangedDockStateChangedadd_DockStateChangedremove_DockStateChangedMovedadd_Movedremove_MovedDestroyadd_Destroyremove_DestroyRibbonHostWindowSizeEventArgsHostSizeChangedadd_HostSizeChangedremove_HostSizeChangedContextualTabDisplayedadd_ContextualTabDisplayedremove_ContextualTabDisplayedget_RibbonControlRibbonDockget_DockStateget_Visibleset_Visibleget_KeepFocusRibbonPaletteSet_PaletteSetTitleBarLocationChangeget_RibbonContentsget_NonSelectionBasedContextualTabsLoadRibbonTabThemeGetTabThemeLoadRibbonContentShouldLoadWorkspaceSettingsFromCUIDateTimeGetHeaderPartDateStampAddRulesTabUpdateContextualTabsLoadTabContentsSetThemeResizeControlVisualHandleKeepFocusRibbontab_ActivatedLoadTabContentRibbonPanelLoadPanelContentCustomizationElementTOnSelectionChangedOnSystemVariableChangedBeginDoubleClickEventArgsOnBeginDoubleClickOnVisibleChangedRibbonControl_UnloadedRibbonControl_LoadedSetRibbonStateRibbonContextMenuEventArgsRibbonControl_ContextMenuOpenedRibbonControl_ContextMenuClosedRibbonMenuToolPaletteGroup_ClickRibbonMenuActivateToolPaletteGroup_ClickRibbonMenuUndock_ClickRibbonMenuClose_ClickRibbonMenuCustomize_ClickRibbonMenuHelp_ClickInvokeRibbonHelpPalettePersistEventArgsRibbonPaletteSet_SaveSizeChangedEventArgsRibbonControl_SizeChangedPaletteSetSizeEventArgsRibbonPaletteSet_SizeChangedRibbonPaletteSet_MovedPaletteSetHelpEventArgsRibbonPaletteSet_HelpRemoveContextualTabsPaletteAddContextMenuEventArgsRibbonPaletteSet_PaletteAddContextMenuRibbonPaletteSet_DestroyPaletteShowDockBarEventArgsRibbonPaletteSet_PaletteSetShowDockBarRibbonMenuCustomizeInPaletteSet_ClickRibbonMenuHelpInPaletteSet_ClickRibbonMenuAutoHideTabs_ClickRibbonMenuAutoHidePanels_ClickRibbonMenuAutoHideNone_ClickRibbonMenuShowPanelTitle_ClickDocumentManager_DocumentCreatedDocumentManager_DocumentDestroyedLayoutEventArgsCurrent_LayoutSwitchedIPEUpdateUIEventArgsIPEEventManager_UpdateUITableSubSelectFilterEventArgsTableSubSelectFilter_CellSelectedActiveThemeColor_ColorThemeChangedApplicationEventManager_ApplicationMainWindowMovedRaiseMovedEventRaiseHostEventRibbonHostEventTargetsOnHostEventGetItemUpdateDockedRibbonHeightmRibbonControlmbRestoreRibbonm_bRibbonWasVisiblembLoadedmnLastIdleTickCountmbResizeOnIdlemCurrWorkspacemSelectionManagermRibbonContentsmActivateContextualTabsmNonSelectionBasedContextualTabsmbIgnoreActivateEventmOldWndProcmNewWndProcmbInPlotPreviewRibbonAutoHideModemPrevAutoHideModembLoadRibbonOnIdleDockStateVisibleKeepFocusRibbonContentsNonSelectionBasedContextualTabsDocumentToBeDestroyedDocumentDestroyedLayoutSwitchedIPEUpdateUICellSelectedSystemVariableChangedAcadApplicationIdleget_EventTypeset_EventTypemnEventTypeEventTypeget_DisplayedTabsget_HiddenTabsmDisplayedTabsmHiddenTabsDisplayedTabsHiddenTabsAliasKeyGetAliasUninitializeIsItemFromSelectionTriggeredContextualTabFindNearestRibbonItemmDocmLastContextualCommandInputCharactersQueuedEventArgsCommandThroat_InputCharactersQueuedGetRibbonSelectModemRibbonPaletteSetRibbonPaletteSetCreatedadd_RibbonPaletteSetCreatedremove_RibbonPaletteSetCreatedget_RibbonPaletteSetset_RibbonPaletteSetCreateRibbonPaletteSetGetRibbonDynamicHelpDataSystem.XmlXmlWriterWriteRibbonItemWriteRibbonSplitButtonWriteRibbonSplitButtonChildEnableRibbonForRenderEnableItemForRenderRibbonPaletteSet_ContextualTabDisplayedInitializeTabsCompareTabNamesShowMTextRibbonTabmsTabmsPanelmsDropDownmRenderEnablePanelListmRenderEnableItemListmRenderEnableHwndListmbRenderActivemDisabledTabsMTextTabIDSendStringToExecuteInt32RectBitmapSizeOptionsGetBitmapSourceFromHBitmapRemoveAccessKeyRibbonButtonStyleCopyRibbonButtonStyleRibbonSplitButtonListStyleConvertRibbonSplitButtonListStyleRibbonSeparatorStyleConvertRibbonSeparatorStyleRibbonResizeStylesRibbonPanelResizeStyleConvertRibbonPanelResizeStyleConvertRibbonAutoHideModeRibbonLockModesConvertRibbonLockModesGalleryDisplayModeConvertGalleryDisplayModeRibbonSplitButtonBehaviorCopySplitButtonBehaviorReadRibbonWorkspaceDataWriteRibbonWorkspaceDataWSRibbonPanelSourceReferenceCopyRibbonPanelPropertiesCopyRibbonControlPropertiesCreateRibbonElementCreateCustomizationRibbonElementAliasCollectionGetAliasesPropertyChangedEventHandlerPropertyChangedadd_PropertyChangedremove_PropertyChangedPoint3dPropertyOnPointChangedAutodesk.AutoCAD.GeometryPoint3dget_Point3dset_Point3dget_Xset_Xget_Yset_Yget_Zset_ZXYZSourceStringPropertyTargetStringPropertyget_SourceStringset_SourceStringget_TargetStringset_TargetStringOnSourceStringChangedOnTargetStringChangedSourceStringTargetStringFilterEventArgsDimensionCollectionViewSource_FilterChildStyleSuffixIndexget_OnMacroset_OnMacroget_OffMacroset_OffMacrok__BackingFieldk__BackingFieldOnMacroOffMacroget_SystemVariableset_SystemVariablek__BackingFieldRenderTargetBitmapDrawColorBoxConvertColorUnlockedContentLockedFormatLockedContentAndFormatLockedk__BackingFieldFilteredCollection_Filterget_FilteredItemsset_FilteredItemsk__BackingFieldFilteredItemsAddColorIfNotContainConvertToStringConvertFromStringAutodesk.AutoCAD.Windows.DataIDataItemIsLayerFrozenOrOffOnSourceChangedNotifyCollectionItemsChangedEventArgsOnItemsChangedINotifyCollectionItemsChangedSubscribeSourceEventsget_Commandset_Commandk__BackingFieldStandardConverterm_converterSourceTypePropertyTargetTypePropertyOnSourceTypeChangedOnTargetTypeChangedget_SourceTypeset_SourceTypeget_TargetTypeset_TargetTypeSourceTypeTargetTypeget_Sourceset_Sourceget_Targetset_TargetSourcePropertyCoerceValueCallbackSourceTargetget_TextBoxTextset_TextBoxTextget_IsReadOnlyset_IsReadOnlymIsReadOnlymTextBoxTextTextBoxTextIsReadOnlymSMManagerCloseResetParamPlayStatusChangedgetCipStopOrPauseModeNameShowMotionViewsControl_PerformTaskSequenceTaskShotTaskget_SMControlmbPausembSeqPausemShotNamemSeqNamembLoopSMControlmCipUeIdmCipDlgNamemCipCategorymCipRegistryPathmCipRegistryKeyOnCancelOnOKOnHelpHideableDialogSettingsControlmHideableDialogSettingsControlokCancelHelp_StackPanelokButtoncancelButtonhelpButtonToolTipmToolTipGetToolTipControlShowIsOpenShowCurrentCommandToolTipHelpHelpSourcePropertyHelpTopicPropertyGetHelpSourceSetHelpSourceGetHelpTopicSetHelpTopicget_UriSourceset_UriSourceget_AdditionalUriSourcesset_AdditionalUriSourcesget_SourceKeyset_SourceKeymUriSourcemAdditionalUriSourcesmSourceKeymUriToResourceDictionaryMapUriSourceAdditionalUriSourcesSourceKeyLoadToolTipFromUriKeyRibbonToolTipCreateToolTipUriKeyCreateUriKeymbShowCLICommandmbShowUserTagApplication_SystemVariableChangedget_ShowToolTipset_ShowToolTipget_ShowShortcutset_ShowShortcutget_ShowCLICommandset_ShowCLICommandget_ShowUserTagset_ShowUserTagget_ShowExtendedContentset_ShowExtendedContentget_ExtendedContentDelayset_ExtendedContentDelayShowToolTipShowShortcutShowCLICommandShowUserTagShowExtendedContentExtendedContentDelayresourceManagerGetStringGetObjectget_Resourcesget_RibbonResourcesmRibbonResourceDictionarymResourceDictionaryRibbonResourcesUserConfigurationManager_CurrentProfileSavingRaiseCanExecuteChangedInvokeProductHelpget_TopicIsValidParseGetTopicFromMacroExtractFirstWordmHelpSourcemHelpTopicTopicdefaultInstanceget_DefaultDefaultBasicContentPropertyHelpIdPropertyHelpPrefixPropertyShowHelpPropertyShowF1HelpStringPropertyHelpContentPropertyBasicContentMarginPropertyIsValidHelpPrefixContextHelpToolTip_LoadedOnVisualParentChangedget_BasicContentset_BasicContentget_HelpPrefixset_HelpPrefixget_HelpIdset_HelpIdget_HelpSourceset_HelpSourceget_ShowHelpset_ShowHelpget_ShowF1HelpStringset_ShowF1HelpStringget_HelpContentset_HelpContentThicknessget_BasicContentMarginset_BasicContentMarginmParentToolTipAutodesk.Private.WindowsContentSourcemHelpContentBasicContentHelpPrefixHelpIdHelpSourceShowHelpShowF1HelpStringHelpContentBasicContentMarginAutoDistanceAngleLineTypeLineWeightTitlePropertyPropertiesPropertyset_Titleget_Propertiesset_PropertiesSavePropertiesget_Nameset_Nameget_PropertyTypeset_PropertyTypeget_Symbolget_FormattedValueget_LUPrecisionget_AUPrecisionInitmsNamemValuemnPropertyTypemsFormattedValueNameSymbolFormattedValueLUPrecisionAUPrecisionmColorITypeDescriptorContextCanConvertFromConvertFromConvertToget_SymbolColorset_SymbolColorget_ColorNameset_ColorNamemColorNameSymbolColorColorNameget_SymbolHeightmnLineWeightSymbolHeightTitleIsBoldPropertyTitleAlignmentPropertyPreviewPropertyPreviewSizePropertyPreviewStretchDirectionPropertyDetailsPropertyShowPreviewPropertyShowDetailsPropertyShowSeparatorPropertyAdjustPreviewSizePropertyget_TitleIsBoldset_TitleIsBoldTextAlignmentget_TitleAlignmentset_TitleAlignmentset_Previewget_PreviewSizeset_PreviewSizeStretchDirectionget_PreviewStretchDirectionset_PreviewStretchDirectionget_Detailsset_Detailsget_ShowPreviewset_ShowPreviewget_ShowDetailsset_ShowDetailsget_ShowSeparatorset_ShowSeparatorget_AdjustPreviewSizeset_AdjustPreviewSizeTitleIsBoldTitleAlignmentPreviewSizePreviewStretchDirectionDetailsShowPreviewShowDetailsShowSeparatorAdjustPreviewSizeget_IsInPaperSpaceget_IsInModelSpaceget_IsInBlockEditorget_IsAuthorPaletteVisibleget_IsToolPaletteVisibleget_IsDashboardVisibleget_IsPropertiesVisibleget_IsQuickCalcVisibleget_IsExternalReferencesVisibleget_IsLayerVisibleget_IsSheetSetManagerVisibleget_IsMarkupSetManagerVisibleget_IsDesignCenterVisibleget_IsLightsVisibleget_IsMaterialsVisibleget_IsVisualStylesVisibleget_IsAdvancedRenderSettingsVisibleget_IsDbConnectVisibleget_IsSunStatusEnabledget_XRayModeValueget_IsAdjustExposureEnabledIsInPaperSpaceIsInModelSpaceIsInBlockEditorIsAuthorPaletteVisibleIsToolPaletteVisibleIsDashboardVisibleIsPropertiesVisibleIsQuickCalcVisibleIsExternalReferencesVisibleIsLayerVisibleIsSheetSetManagerVisibleIsMarkupSetManagerVisibleIsDesignCenterVisibleIsLightsVisibleIsMaterialsVisibleIsVisualStylesVisibleIsAdvancedRenderSettingsVisibleIsDbConnectVisibleIsSunStatusEnabledXRayModeValueIsAdjustExposureEnabledWM_USERWM_ACAD_KEEPFOCUSWM_MDIACTIVATEWM_USER_SIZEGWL_WNDPROCUM_ADUI_SHOWDOCKBARGetCursorPositionSetCursorPositionGetParentDestroyWindowSendMessagePostMessageGetWindowRectGetCursorPosSetCursorPosEnumChildWindowsGetCaptureSetWindowLongCallWindowProcDeleteObjectLeftTopRightBottomCreateInstanceSystem.ReflectionPropertyInfoGetPropertyValueSetPropertyValueDelegateCreateDelegateEventInfoAddEventHandlerproductNamemaxRecentFilessenderebZeroDocopenDocsmaxCountrecentDocsnewRecentDocsrecDocsobjectmethodcallbackresulthandledllnamehModulehInstanceuIDlpBuffernBufferMaxhInstlpszExeFileNamenIconIndexlpszFilephIconLargephIconSmallnIconsstrFullDocNamestrExtbSmallIconsTextwritablemenuItemscurrentItemskeyParentsKeyNameqatSourcemenuContenttabsmacrossearchTextfeedbacksearchRecordsbestMatchesnormalMatchesrelativeMatchesresultsvaluekeywordsSearchTextsearchKeybasePathtextrecordsitemitemTitlemacrocmdItemitemPathgroupNameitemsimagetagrelativeMatchTypematchTypebEnablesIDmenuGroupDataworkspacesquickAccessToolbarItemsworkspaceNamebAddmenuGroupcustSectionprefixtoolbarIdOutAttributetoolbarElementsIdnewItemoldItemnewIndexoldIndexactionwsmenuGroupNameorientationlocationdictidelementparameterddisplayNameacadColorindextypeTargetparamculturewidthargsmainMessagedetailMessageimageUrirootKeysubKeynameresReqIdCourseIdModuleIdcurrentVersionconnectionIdtargetmessageIdappNametitlexamliLeveliPrevLevelItemlayoutsQuickViewManagerbRegenAllhWndhwndnLevelbPinbUpdateDatabUpdateMarginfinalWidthdurationxFinalMarginsmIndexgetListBoxDatabIsPinnedselectiStartIndexlevelntbbtnbdrbBiglbimouseEnterLBIlbscrollToqvLevelarrowNamecurrentLevelunhighlightBordertaskSourceoldNamenewNameprevLevelcurLevelqvCtrlperformQVCommandcmdqvCommandcommandiLevelItemCloseAllkeybLoopbPauseAllPlayobjrdbuttonNameroutedEventHandlerstackPanelparentMenuchildMenuHeadercontextMenumenuHeaderbEnableddoccipvalueactivatewrapUpInactiveDocechoCommandsAttributeValuedbdocumentsQuickViewManagerdocNameqvDataListqvCtrlHeightbTopbLeftiLevelItemdocumentNameiItemcipcommandlayoutListownerlisttypebmqvLayoutListeThumbnailnItemstargetTypefVallenslengthfieldOfViewuidthemetriggercoderulelastselectorsassemblyPathlistItemhistoryButtonbUndosMenuMacrosMenuMacroIdsourcehwndParentcommandHandlercommandParametercoldictssupportedControlsvisitedbCloneitemOutsMenuGroupNamesFileNamemenuMacrosribbonRootribbonElementpanelSourcefileNamemenumacrosmenuGroupsribbonWorkspaceribbonContentswsRibbonRootribbonControltabIdtoolpaletteGroupresolveRefDatamacroIdpanelSourceElementmenugroupnametoolTipDatasplitElementdataBoundDropDownElementpreviewdbObjcommandNameMsgwParamlParammainDatadateStampbFromDoubleClickbLoadContextualrootVisualribbonTabcontentrefElementcMenunEventTypenTargetbStopIfHandleddisplayedTabshiddenTabstabpanelpswriterrItemrTabTitlerPanelSourceTitlebSlideOutPanelrDropDownButtonrRowIsInSlideOutPaneldropDowncommandIdisInSlideoutbRenderingitemEnabledbShowabmTextTabsMacrobCancelCurrentCmdbRestoreSelectionbMenuMacrosPanelNamebitmappalettesourceRectsizeOptionshBitmapbuttonStylesizestylemodebehaviorsplitButtonpanelRefworkspaceparentseparatorbuttondropdowncontrolaliasesvaluestargetTypescolorinfostringValueoldSourcenewSourceremovepropertyNamesmbStopxyimmediatelyelvaluriSourceuriKeytooltiptooltipDatastrIDoldParentsNamenPropertyTypeclrcontextsourceTypedestinationTypelwptlpRectparentHandlenIndexnewProclpPrevWndFunclefttoprightbottompropertyInfodelegateTypehandlereventInfoAssemblyConfigurationAttributeAssemblyVersionAttributeAssemblyDescriptionAttributeAssemblyTitleAttributeThemeInfoAttributeResourceDictionaryLocationCommandClassAttributeExtensionApplicationAttributeSystem.DiagnosticsDebuggableAttributeDebuggingModesSystem.Runtime.CompilerServicesCompilationRelaxationsAttributeRuntimeCompatibilityAttributeSystem.CoreExtensionAttributeAcWindowsApplicationDocumentCollectionget_DocumentManagerget_CountDocumentCollectionEventHandleradd_DocumentActivatedadd_DocumentToBeDestroyedUserConfigurationManagerget_UserConfigurationManagerProfileEventHandleradd_CurrentProfileChangingadd_BeginQuitComponentManagerApplicationMenuget_ApplicationMenuadd_Closingadd_OpeningCuiEventManagerLoadRibbonEventHandleradd_LoadRibbonget_OptionsButtonset_IsVisibleget_ItemDataTemplateset_SearchResultItemTemplateget_SearchableContentsClearDisposableWrapperop_Inequalityget_QuickAccessToolBarRibbonDataGetMenuGroupsEnumeratorGetEnumeratorget_Currentget_PartialMenusMoveNextget_MenuContentget_Itemsset_MenuContentset_IsSearchEnabledset_CommandHandlerget_ExitButtonStringIsNullOrEmptyHostApplicationServicesget_ProductFormatBindingDataBindingsget_UIBindingsBindingBaseset_CommandHandlerBindingIEnumeratorDocumentItemset_FullNameget_FullNameSystem.IOPathGetFileNameset_PreviewImageget_PreviewImageFileGetLastWriteTimeset_LastWriteTimeget_LastWriteTimeset_LastAccessTimeGetExtensionset_LargeImageFileStreamOpenReadStreamget_Lengthset_FileSizeAbortget_RecentDocumentsIEnumerator`1get_PathUriKindTryCreateget_IsLoopbackget_CurrentDispatcherParameterizedThreadStartStartop_Equalityget_LastAccessTimeget_FileSizeget_Versionset_Versionget_CurrentlyOpenByset_CurrentlyOpenByget_LastSavedByset_LastSavedByDispatcherPriorityget_OpenDocumentsGetValueDocumentViewRuntimeTypeHandleGetTypeFromHandleset_DocumentViewDocumentGroupByset_DocumentGroupByDocumentListTypeset_DocumentListTypeget_DocumentViewSetValueget_DocumentGroupByget_DocumentListTypeStructLayoutAttributeLayoutKindMarshalAsAttributeUnmanagedTypeDllImportAttributeuser32.dllkernel32.dllShell32.dllConcatTryGetValueRegistryClassesRootOpenSubKeyEmptyEnvironmentget_SystemDirectoryLastIndexOfSubstringInt32IntPtrZeroContainsKeyset_Itemget_EmptyFromEmptyOptionsImagingCreateBitmapSourceFromHIconget_IsAbsoluteUriget_IsFileget_AbsoluteUriXmlTextReaderXamlReaderXmlReaderLoadComponentContainsSystemObjectsDynamicLinkerget_DynamicLinkerget_ProductKeyGetSystemVariableCurrentUserGetSubKeyNamesRibbonMenuItemset_Idset_CommandParameterset_ToolTipget_ToolTipset_IsToolTipEnabledset_Descriptionget_Descriptionset_HelpTopicset_KeyTipset_IsSplitInsertExceptionToolBarSourceValidatingRibbonItemCollectionget_IsSearchCanceledValueCollectionget_ValuesRibbonPanelCollectionget_Panelsget_Ribbonget_IsVisibleStringCollectionget_IsContextualTabget_Tagget_SmallImageget_LargeImageRibbonListButtonset_Currentset_Tagget_IsCheckedBindingBindingOperationsBindingExpressionBaseSetBindingget_CharsCharIsWhiteSpaceRemoveAtTrimEndsWithSystem.Text.RegularExpressionsRegexEscapeTrimStartMatchRegexOptionsCaptureIsLetterOrDigitNextMatchGroupget_SuccessReplaceCompareget_CLICommandget_UserTagget_ToolTipDataget_CommandParameterRibbonToolTipBaseget_CustomContentStringComparisonget_HasItemsget_IsSplitRibbonComboRibbonGalleryRibbonSliderset_GroupNameset_Pathset_IsEnabledget_HelpTopicFrameworkPropertyMetadataset_BindsTwoWayByDefaultBooleanPropertyMetadataRegisterget_HelpButtonget_IsQuiescentremove_Idleget_NonInPlaceMainWindowadd_Idleadd_BeginCustomizationModeadd_EndCustomizationModePaletteSetStateEventHandleradd_StateChangedAddStandardItemset_HasCustomizeCommandWorkspaceRestoreEventHandleradd_WorkspaceRestoreWorkspaceRibbonSaveEventHandleradd_WorkspaceRibbonSaveNotifyCollectionChangedEventHandleradd_CollectionChangedILookup`1get_SystemVariablesSubSettingset_CustomizeCommandIsSysVarEnabledInt16set_IsMenuBarVisibleset_IsShowMenuBarCommandVisibleQuickAccessStandardCommandsset_DefaultCommandsget_CustomizeVisibilityItemsget_MenuGroupTypeget_Orientationget_CUIFileNameMenuGroupget_MenuGroupQuickAccessToolbarCollectionget_QuickAccessToolbarsCollectionBaseget_RibbonItemsget_ElementIDFormatIdWorkspaceCollectionget_Workspacesget_WorkspaceQuickAccessToolbarget_ToolbarIdAppendIssueUIDFromCustomizationSectionItemsCollectionSetModifiedItemsElementBaseset_ParentCombineProfileManagerLoadDataQuickAccessToolbarUtilReadQuickAccessToolbarItemsget_QuickAccessToolBarLocationset_OrientationWriteQuickAccessToolbarItemsQuickAccessToolbarStandardItemSplitIdget_ReadOnlyset_ToolbarIdset_WorkspaceQuickAccessToolbarset_MenuGroupget_IsBelowRibbonCommandVisibleGCHandleUtilsIsInCustomizeModeGetCustomizationSectionHandleToIntPtrIsModifiedFreeCustomizationSectionHandleAcadTaskDialogsTaskDialogCreateFromFileget_MainWindowget_Handleget_PropertyNameget_CurrentWorkspaceNameget_UIDset_UIDget_Workspaceget_CustomizationSectionset_QuickAccessToolBarLocationSaveDataget_InfoCenterToolBarget_NewItemsICollectionget_OldItemsget_NewStartingIndexget_OldStartingIndexget_ActionStateEventIndexget_NewStateKeyValuePair`2get_KeyStringEnumeratorCompilerGeneratedAttributeCommandMethodAttributeCommandFlagsget_MdiActiveDocumentAutodesk.AutoCAD.EditorInputEditorget_EditorPromptResultPromptStatusget_Statusget_StringResultFindTabWriteMessageset_ActiveTabCipUtilsIsOperationalgetMacroStringWaypointReachedWithStringAttReferenceEqualsEditorBrowsableAttributeEditorBrowsableStateset_ShowActivatedset_AllowsTransparencyRibbonCommandItemCollectionget_FrameButtonsICloneableset_Ownerset_ContextMenuContentControlVerticalAlignmentset_VerticalContentAlignmentset_MarginInvalidOperationExceptionPropertyChangedCallbackset_AffectsRenderget_NewValueSelectorget_SelectedIndexset_SelectedIndexStyleset_StyleItemsControlIEnumerableset_ItemsSourceSelectionChangedEventHandleradd_SelectionChangedadd_DocumentCreatedadd_DocumentBecameCurrentIndexOfComboBoxItemColorMethodFromColorIndexUtilitiesReservedStringEnumTypeGetReservedStringset_IsDropDownOpenItemContainerGeneratorget_ItemContainerGeneratorContainerFromIndexset_IsSelectedget_AddedItemsget_RemovedItemsColorDialogNullable`1ShowModalget_SelectedItemFromRgbset_DefaultValueget_ColorNameForDisplayValueConversionAttributeget_Rget_Gget_BColorsget_Whiteget_IsByColorget_Redget_Greenget_Blueget_IsNoneget_IsByBlockget_IsByLayerget_WorkingDatabaseTransactionManagerget_TransactionManagerTransactionStartTransactionObjectIdget_ClayerOpenModeLayerTableRecordCommitget_IsByAciget_ColorValueKeyget_DataContextSerializableAttributeRegisterAttachedTextBoxBaseFocusSelectAllset_BorderThicknessget_BackgroundBrushesSolidColorBrushset_Backgroundget_CurrentCultureFlowDirectionget_FlowDirectionFontFamilyget_FontFamilyFontStyleget_FontStyleFontWeightget_FontWeightFontStretchget_FontStretchTypefaceget_FontSizeget_BlackFormattedTextget_Widthget_MaxWidthTextWrappingset_TextWrappingget_PropertyDefaultStyleKeyPropertyOverrideMetadataDoubleFrameworkPropertyMetadataOptionsControlTemplateget_TemplateFrameworkTemplateFindNameButtonBaseadd_Clickget_Heightset_Heightset_WidthKeyEventHandleradd_PreviewKeyDownadd_LostFocusget_RegistryProductRootKeyProcessget_InfoCenterPaletteManageradd_ICQueryadd_IcLaunchadd_HelpClickedInfoCenterget_InfoCentermInitWidthadd_TickTimeSpanset_IntervalStopGetApplicationFrameHWndCreateInfoCenterHwndSourceget_InfoCenterToolBarHostset_HostInfoToolbarMoveDelegatem_pToolbarMoveDelegateInfoToolbarResizeTom_pToolbarResizeDelegateadd_ToolbarFocusChangedadd_InfoToolbarButtonClickedIconget_DefaultWindowIconVisualsget_ApplicationIconset_DefaultWindowIconget_TemporaryRolloutInfoToolbarSizeChangedget_Initializedset_KeepFocusRefreshShowBalloonStringReaderTextReaderPanelUIElementCollectionget_ChildrenStretchset_StretchEncodingget_ASCIIget_Programget_LocalRootFolderUserDataFilePathProductHKCUPathProductHKLMPathLocaleVersionLocalMachineSerialNumberProductPathProductMsiGuidProductNameVersionProductNameGetTypeTypeDescriptorGetConverterConvertFromInvariantStringget_ProductLcidToInt32get_PaletteIndexget_QueryTextLogIcQuerymIcTypemGroupmCategorymUrlLogIcLaunchget_IsChmFileFileInfoSetUaLaunchTypeFileSystemInfoget_Extensionget_ChmFilenameFindFileHintFindFileSystem.Windows.FormsHelpHelpNavigatorDebuggerNonUserCodeAttributeget_NavigateUriget_OriginalStringset_NavigateUriRegistryKeyPermissionCheckCreateSubKeyHideableDialogSettingsDictionaryget_HideableDialogSettingsDictionaryGetResultSetResultEnqueueDequeueSystem.CodeDom.CompilerGeneratedCodeAttributeSizeToContentset_SizeToContentWindowStyleset_WindowStyleset_ShowInTaskbarget_Transparentadd_DeactivatedCancelEventHandleradd_ClosedMouseEventHandleradd_MouseLeaveadd_MouseEnteradd_KeyDownadd_SourceInitializedSetQuickViewWindowHandleHideget_ChangedCompareOrdinalget_ActualHeightget_IsActiveSystemVariableChangedEventHandleradd_SystemVariableChangedSystemEventsadd_DisplaySettingsChangedDocumentDestroyedEventHandleradd_DocumentDestroyedApplicationEventManagerApplicationMainWindowMovedEventHandleradd_ApplicationMainWindowMovedApplicationMainWindowSizedEventHandleradd_ApplicationMainWindowSizedadd_EnterModaladd_LeaveModalBeginPlotEventHandleradd_BeginPlotEndPlotEventHandleradd_EndPlotVisibilityget_Visibilityset_VisibilityPlotTypeget_PlotTyperemove_SystemVariableChangedremove_DisplaySettingsChangedremove_DocumentDestroyedremove_ApplicationMainWindowMovedremove_ApplicationMainWindowSizedremove_Tickremove_EnterModalremove_LeaveModalremove_BeginPlotremove_EndPlotget_WindowStateFromMillisecondsWindowCollectionget_OwnedWindowsSetSystemVariableget_DatabaseNullReferenceExceptionremove_DocumentActivatedget_DocumentScrollToHorizontalOffsetget_Parentget_TemplatedParentTimelineremove_Completedset_Durationset_Toadd_Completedget_ItemsSourceAnimationTimelineBeginAnimationMarginPropertyget_IsEditorReadyScreenget_AllScreensRectangleget_WorkingAreaget_Leftget_RightCollectionViewContentPresenterop_ImplicitMouseDeviceget_MouseDeviceIInputElementGetPositionPointToScreenget_Deltaget_ContentTemplateInvalidCastExceptionget_ActualWidthget_HorizontalOffsetget_ScrollableWidthget_DeviceIndependentLocationget_DeviceIndependentSizeFindResourceset_ItemContainerStyleItemsPanelTemplateset_ItemsPanelLinearGradientBrushset_BorderBrushKeyboardKeyStatesGetKeyStatesget_MarginImageAlignerDecoratorget_ChildEventSetterRoutedEventScrollChangedEventset_EventScrollChangedEventHandlerset_HandlerSetterBaseCollectionget_SettersSetterBaseMouseButtonEventHandleradd_MouseDownadd_MouseMoveadd_MouseRightButtonUpLoadedEventIsDocumentInBlockEditorCommandHandlerget_ContextMenuSeparatorIsFlagOnHeaderedItemsControlset_HeaderSMManagerUpdateThumbnailSequenceShotUpdateThumbnailAllMoveSequenceShotDeleteSequenceShotMouseButtonStateget_LeftButtonget_ClickCountPlayModePlayActionGetPlayStatusIsShotPlayingremove_Click{7F99BECA-AD15-4CAB-86F6-211E0DF83CBD}__StaticArrayInitTypeSize=26$$method0x60002a2-1RuntimeHelpersArrayRuntimeFieldHandleInitializeArrayIndexOfAnyRenameSequenceShotContextMenuEventHandleradd_ContextMenuOpeningVisualTreeHelperGetChildrenCountGetChildSendMenuStringToExecuteget_LayoutDictionaryIdIsBoxedset_Enabledadd_DictionaryModifiedadd_ObjectModifiedremove_DictionaryModifiedremove_ObjectModifiedDatabaseIOEventHandleradd_SaveCompleteremove_SaveCompleteget_ThumbnailBitmapFreezeBeginInitEndInitGetDwgFrameIconToBitmapMemoryStreamSystem.Drawing.ImagingImageFormatget_PngSeekOriginSeekset_StreamSourceStatusBarget_StatusBarset_Leftget_Windowset_TopDocumentWindowCollectionget_DocumentWindowCollectionArrangeIconsTileVerticallyTileHorizontallyCascaderemove_DocumentCreatedget_OriginalFileNameQVDrawingCloseAllOtherDrawingsCloseAndDiscardCloseAndSaveQVDrawingCloseReadOnlyCOMExceptionset_WindowStateget_FilenameClipboardDataFormatsUnicodeTextSetDataset_MdiActiveDocumentDocumentLockLockDocumentset_CaptureOnLayoutSwitchLayoutManagerset_CurrentLayoutStandardInvalidNameEmptyNameStandardInvalidNameTooLong$$method0x6000319-1StandardInvalidNameUnsupportedCharactersStandardDuplicateNameErrorset_DecodePixelWidthThumbnailCaptureFlagsEnumerateLayoutThumbnailsget_LayoutNameget_Thumbnailget_IsLayoutEmptyOpenCloseTransactionStartOpenCloseTransactionDBDictionaryDbDictionaryEnumeratorDBDictionaryEntryLayoutCompareToset_TabSelectedToDoubleDoNothingFormatExceptionNumberStylesIFormatProviderMathAtanConverterAngularUnitFormatStringToAngleTanAngleToStringLog10PowGetDateTimeFormatsget_DayOfYearget_Todayget_YearDateTimeKindAddDaysget_Ticksget_TimeOfDayget_TotalMinutesAddMinutesContentPropertyAttributeFlagsAttributeAppDomainget_CurrentDomainget_BaseDirectoryDirectorySearchOptionGetFilesExistsGetLastWriteTimeUtcop_LessThanFileModeFileAccessFileShareOpenReadAllBytesAppendFormatb__0Comparison`1CS$<>9__CachedAnonymousMethodDelegate1SortCopyToMicrosoft.CSharpCSharpCodeProviderCompilerParametersget_ReferencedAssembliesPropertyDescriptorget_LocationGetExecutingAssemblyset_GenerateExecutableset_GenerateInMemoryset_IncludeDebugInformationset_OutputAssemblyCodeDomProviderCompilerResultsCompileAssemblyFromSourceCompilerErrorCollectionget_Errorsget_HasErrorsCompilerErrorget_ErrorTextadd_DropDownOpenedget_ApplicationStatusBarMenuget_IsCheckableget_HeaderExecuteApplicationStatusBarMenuExecutedRoutedEventHandlerCanExecuteRoutedEventHandlerCommandBindingCommandManagerRegisterClassCommandBindingget_Parameterget_DocumentActivationEnabledset_CanExecuteRibbonListButtonStyleset_ListButtonStyleadd_DropDownClosedset_IsCheckableadd_Initializedset_EnableUsingCommandHandlerGetSelectedItemsadd_DropDownOpeningIsUndoAvailableIsMultiRedoAvaliableGetRedoHistoryGetUndoHistoryArgumentNullExceptionNotifyPropertyChangedget_CommandHandlerget_CommandHandlerBindingObsoleteAttributeFindParentSetFocusToDwgViewIComparableDefaultValueAttributeCreateHwndControlCreateInvalidHwndControladd_ToolTipOpenedadd_ItemInitializedget_MenuItemsGetValueNamesget_MergedDictionariesKeyCollectionStartsWithget_KeyTipContextualTabDisplayTypeget_DisplayTypeset_IsMergedContextualTabget_AliasesRibbonPanelSourceCollectionget_RibbonPanelSourcesRibbonTabSourceCollectionget_RibbonTabSourcesget_ShowPanelTitleInHorizontalRibbonset_ShowPanelTitleInHorizontalOrientationget_ShowPanelTitleInVerticalRibbonset_ShowPanelTitleInVerticalOrientationget_AutoHideModeset_AutoHideModeget_LockModeset_LockModeWorkspaceRibbonTabCollectionget_WorkspaceTabsTabIdset_Showset_IsActiveWorkspaceRibbonPanelCollectionget_PanelIdset_PanelIdget_ToolPaletteGroupNameset_ToolPaletteGroupNameRibbonDialogBoxLauncherget_DialogBoxLauncherRibbonCommandHolderget_CommandIDget_Commandsset_DialogLauncherget_CommandHandlerInternalget_DialogLauncherRibbonRowRibbonRowBreakRibbonPanelBreakOrientationget_ButtonStyleget_MacroIDget_GroupNameget_TooltipTitleget_macroRibbonItemSizeget_Sizeget_LargeImageBitmapget_SmallImageBitmapRibbonItemToolTipEventArgsget_DisplayModeset_DisplayModeget_MinWidthIsNaNset_MinWidthget_Behaviorget_Groupingset_IsGroupingRibbonSplitButtonCommandset_EnableHelpget_ListStyleset_ListStyleget_SeparatorStyleset_SeparatorStyleTryGetDatabaseremove_DocumentBecameCurrentremove_DocumentToBeDestroyedget_GlobalCommandNameCommandEventHandleradd_CommandWillStartadd_CommandEndedadd_CommandCancelledadd_CommandFailedremove_CommandWillStartremove_CommandEndedremove_CommandCancelledremove_CommandFailedDockSidesget_Dockget_DockEnabledGuidRibbonDragDropOptionsset_DragDropOptionset_DockEnabledEnableTransparencyDataItemCollectionsget_Collectionsget_SelectionDataItemCollectionBeginDoubleClickEventHandleradd_BeginDoubleClickGetAcadResourceIconset_Iconset_HostWindowPaletteAddVisualPaletteSetStylesset_DockPaletteSetSizeEventHandleradd_SizeChangedPaletteSetMoveEventHandleradd_PaletteSetMovedPalettePersistEventHandleradd_SavePaletteSetDestroyEventHandleradd_PaletteSetDestroyPaletteAddContextMenuEventHandleradd_PaletteAddContextMenuPaletteSetShowDockBarEventHandleradd_PaletteSetShowDockBarPaletteSetTitleBarLocationChangeEventHandleradd_PaletteSetTitleBarLocationChangePaletteSetHelpEventHandleradd_HelpLayoutEventHandleradd_LayoutSwitchedIPEWrapperget_IPEEventManagerUpdateUIEventHandleradd_UpdateUITableSubSelectFilterTableSubSelectFilterEventHandleradd_CellSelectedActiveThemeColorColorThemeChangedEventHandleradd_ColorThemeChangedPaletteSetTitleBarLocationget_TitleBarLocationremove_ActivatedGetDefaultToolTipContentSourcesToolTipSettingsget_ToolTipSettingsget_ContentSourcesset_IsContextualTabadd_ActivatedTabThemesget_Cyanget_Purpleget_Yellowget_CustomThemesget_RibbonRootGetProfileStorageFilenameop_GreaterThanMenuPackageOpenPackageForReadTryGetPartModifiedDateRibbonTabSelectorCollectionget_RibbonTabSelectorsRibbonTabSelectorget_Ruleget_ShowRibbonPanelOrientget_ShowPanelTitleInHorizontalOrientationset_ShowPanelTitleInHorizontalRibbonget_ShowPanelTitleInVerticalOrientationset_ShowPanelTitleInVerticalRibbonget_ActiveTabHideContextualTabget_IsMergedContextualTabShowContextualTabColorThemeEnumget_CurrentThemeThemesget_Lightget_Darkset_CurrentThemeset_DeviceIndependentSizeRecalculateDockSiteLayoutPresentationSourceFromVisualIKeyboardInputSinkHasFocusWithinget_FocusedElementResetHeightRibbonPanelSourceReferenceCollectionRibbonPanelSourceReferenceExtractIdset_IsFloatingget_XCoordinateget_YCoordinateset_InitialFloatingLocationget_IsFloatingget_FloatingGroupset_FloatingGroupget_FloatingOrderset_FloatingOrderget_FloatingOrientationset_FloatingOrientationget_ResizeStyleset_ResizeStyleCommandStackget_ActiveCommandsget_AllCommandsremove_UnloadedSizeChangedEventHandlerremove_SizeChangedremove_ContextMenuOpenedremove_ContextMenuClosedadd_Unloadedadd_ContextMenuOpenedadd_ContextMenuClosedVariablesget_VariablesVariableget_CurrentAutoHideModeRibbonContextMenuTargetGetToolPaletteGroupsget_RibbonOrientationIsTextEditorActiveget_PaletteSizeget_RemoveMenuItemsset_CheckedMenuMenuItemCollectionget_IsCuiCommandEnabledremove_StateChangedremove_Saveremove_PaletteSetDestroyremove_PaletteAddContextMenuremove_PaletteSetShowDockBarremove_PaletteSetTitleBarLocationChangeremove_Helpremove_LayoutSwitchedremove_UpdateUIremove_CellSelectedremove_WorkspaceRestoreremove_WorkspaceRibbonSaveremove_LoadRibbonremove_ColorThemeChangedget_ShowDockBarget_TickCountHostEventEventset_RoutedEventset_OriginalSenderset_OriginalEventArgsget_OriginalSenderRaiseEventset_PanelBarMinHeightInputCharactersQueuedEventHandlerCommandThroatadd_InputCharactersQueuedremove_InputCharactersQueuedRibbonListPopupget_ClosingPopupget_CharactersToUpperInvariantget_SysVarInProgressset_IsContinuingXmlWriterSettingsset_OmitXmlDeclarationConformanceLevelset_ConformanceLevelset_IndentCreateGetMenuMacroWriteStartElementToUpperWriteAttributeStringget_CurrentUICultureWriteStringWriteEndElementop_Explicitget_IsPanelEnabledset_IsPanelEnabledLogRibbonItemCommandExecuteToCharDo_CmdGetHbitmapCreateBitmapSourceFromHBitmapFromHbitmapset_Sizeset_ShowTextset_IsSynchronizedWithCurrentItemLoadXmlSaveXmlget_InitialFloatingLocationset_XCoordinateset_YCoordinateget_Cookieset_MacroIDCloneMenuMacroset_MaxWidthFilterEventHandleradd_FilterPropertyDescriptorCollectionGetPropertiesFindset_AcceptedNotSupportedExceptionget_ObjectIdget_IsNullGetFontImageGetVisualStyleImageget_DoNothingUnsetValueToInt16ToBooleanAbsDecimalInt64SByteSingleByteDrawLineTypePatternGetPixelMakeTransparentDrawLineWeightSquareDrawingVisualDrawingContextRenderOpenRectPenDrawRectanglePixelFormatsPixelFormatget_Pbgra32RenderCellStatesColorCollectionget_ColorsAddIfNotContainTextIPEUtilsNoUnitsNumberToStringDistanceToStringStringToDistanceIsLongNonEditableTypeRemoveNonEditableObjectsPropertiesObjectsOnLockedLayersget_IsFrozenget_IsOffPropertiesObjectsMoveToFrozenOrOffLayersICollectionViewget_ViewNotifyCollectionItemsChangedEventHandlerremove_ItemsChangedadd_ItemsChangedIDataItemTransactionCellRangeget_IsSingleCellget_IsContentEditableget_HasValueNotImplementedExceptionget_IsMergedObjectIdCollectionGetDataLinkCellget_TopLeftTableCellTypeget_CellTypeINamedValueget_HasBookNameget_BookNameget_ColorMethodget_IsErasedSymbolTableRecordget_IsDependentLayerManagerCannotMakeCurrentGetSequenceIdsViewTableRecordget_CategoryNameErrorStatusget_ErrorStatusUpdateCachedDataGetShotIdsGraphicsFromImageDrawImageComImportAttributeGuidAttributeInterfaceTypeAttributeComInterfaceTypeEndPlayLoopStatusChangedPauseOrResumePlayBackSmManagerUtilitiesSetSmManagerInterfaceUIToBeShownUIToBeHiddenCIP_LogTargetShotset_DefaultApplicationHideableDialogSettingsset_Categoryget_DefaultApplicationset_Applicationset_DialogResultset_IsHelpEnabledget_IsOpenset_AffectsMeasureset_InheritsAddOwnerget_ExtendedContentSourceget_ExtendedContentKeyset_ExpandedContentget_Shortcutset_Shortcutset_CustomContentget_EnableHelpIConfigurationSectionOpenCurrentProfileOpenSubsectionset_InitialShowDelayOpenGlobalSectionget_IsProgressiveDisplayEnabledset_IsProgressiveDisplayEnabledget_ProgressiveDisplayDelayset_ProgressiveDisplayDelayset_HostServiceset_ApplicationWindowLoadHideableDialogSettingsDictionaryadd_CurrentProfileSavingSaveHideableDialogSettingsDictionaryInvokeHelpForExternalAppMenuUtilOpenDocumentEvaluateDieselSettingsBaseSynchronizedValidateValueCallbackset_IsOpenOperatingSystemget_OSVersionget_Majorset_IndentCharsXamlWriterDesignerSerializationVisibilityAttributeDesignerSerializationVisibilityget_Aset_Aset_Rset_Gset_BDistanceUnitFormatColorConverterTypeConverterAttributeset_AffectsArrangeget_TileModeget_ActiveViewportIdViewportTableRecordAbstractViewTableRecordget_SunIdget_IsValidSunget_IsOnViewportuser32.Dlluser32gdi32.dllActivatorBindingFlagsBinderInvokeMemberAcWindows.g.resourcesAutodesk.AutoCAD.Ribbon.Commands.resourcesAutodesk.AutoCAD.AcInfoCenterConn.AcInfoCenterConn.resourcesAutodesk.AutoCAD.Windows.Properties.Resources.resourcesAutodesk.AutoCAD.Windows.Resources.StringResource.resources?SearchResultItemContentTemplate ExitSNativeFunctions[%prodname%.exe|OnExitApp]%Commands[_Options]MenuNopreviewDocumentViewDocumentGroupBy!DocumentListType _small _largeDefaultIcon\shell32.dll,0\shell32.dll,CPROFILE\Profiles\#\Application MenuInsertBeforeInsertAfter ImageSeparator TextCommand KeyTipTooltipDescriptionHelpSourceHelpTopic After BeforeSearchGroupQAT%SearchGroupAppMenu#SearchGroupRibbon#SearchResultPanel+SearchResultPanelItem > *.* SearchFlyout)SearchDropDownFlyout/MbBestMatchSearchResult+MbRelatedSearchResult!SearchPanelFoundSearchPanel'SearchCommandLoadedIsChecked\Help ButtonTEXTEDITORQUICKCUI;AcRibbonCommandButtonQuickCUIMENUBARWSCURRENT5QuickAccessToolbarRoot.cui#WorkspaceRoot.cui %QuickAccessToolbarID_QAT_/QuickAccessToolbarItemsERibbon.UnableToAddSeparatorIntoQATARibbon.UnableToAddControlIntoQAT9Ribbon.UnableToRemoveFromQATIsVisible *SDI/QV_CommandSDINotAllowedOACCIP_WAYPOINT_QUICKVIEW_DRAWING_OPENEDIACCIP_STATE_QUICKVIEW_DRAWING_OPENEDKACCIP_ATTRIBUTE_QUICKVIEW_OPENED_MODEMODE_CLIMACCIP_WAYPOINT_QUICKVIEW_LAYOUT_OPENEDGACCIP_STATE_QUICKVIEW_LAYOUT_OPENEDAACCIP_WAYPOINT_SHOWMOTION_OPENED;ACCIP_STATE_SHOWMOTION_OPENED?ACCIP_ATTRIBUTE_SHOWMOTION_MODEMODE_AUTHORINGAAutodesk.AutoCAD.Ribbon.Commands!PlusRibbonPromptGError_Specified_Tab_Cannot_Be_Found7QuickPropertiesFrameButtonsqUnexpected. Command parameter must be RibbonCommandItem.SelectedColor#ColorControlStyle NoneRed Yellow Green Cyan BlueMagenta WhiteSelectColor ColorActualTextIsEditable...MaxWidthMaximumMinimum ValueIncrementbuttonSpinUpbuttonSpinDowntextBox\InfoCenterInfoCenterOnFEEDBACK_URLDykTemplate%DykTemplateNoImage: ACAD-SerialNumberLocationProductCodeReleaseInfoCenter .htm=MigrateRibbon_Balloon_HelpFile9MigrateRibbon_Balloon_HelpIdAutoMigrate\CustomizationMigrationPath R17.27MigrateRibbon_Balloon_Title;MigrateRibbon_Balloon_AppName?MigrateRibbon_Balloon_MessageID/AcWindows;component/infocenteracconn/cuiribbonmigrationballoon.xamlGhttp://partnerproducts.autodesk.comInitialSetupMyAutoCADPartenerLinksIndustryArchitectural CivilStructuralMEPManufacturingElectricalDefault%ShowBalloonEnabled/MyAutoCAD_Balloon_Title3MyAutoCAD_Balloon_AppName7MyAutoCAD_Balloon_MessageIDw/AcWindows;component/infocenteracconn/myautocadballoon.xaml[Autodesk.AutoCAD.Windows.Properties.ResourcesPlayMaskImageSTATUSBAR)QVDRAWINGPREVIEWSIZEQV_LayoutsTitleUNPINNED PINNEDQVLAYOUTPINImageHeightScrollOffsetActiveIndexImageTextNameLeftScrollArrow!RightScrollArrowAUTO SCROLLRootPanelDefaultLevel%ControlPanelHolder'QuickViewLevelStyleListBoxStyle1#ListBoxItemStyle1'ItemsPanelTemplate1LeftArrowButton!RightArrowButtonmOuterBorderMQuickViewThumbBorderBackgroundRolloverOQuickViewThumbBorderBorderBrushRolloverOptionsGridOQuickViewThumbBorderBackgroundBrushIdleGQuickViewThumbBorderBorderBrushIdle;../Resources/Images/PinOn.ico=../Resources/Images/PinOff.ico[/AcWindows;component/quickview/quickview.xaml ActiveHasChildImageToolTipLeftButtonImage!RightButtonImageFileTypeIconImageName'IsImageNameEditableCustomData#LeftButtonToolTip%RightButtonToolTipImageWidthTextBoxMaxWidthCQV_BeditLayoutOptionsNotAvailableLAYOUT RCMWindows/QVMenuMenu_ArrangeIcons+QVMenu_TileVertically/QVMenu_TileHorizontallyQVMenu_Cascade/QVMenu_CopyFilesasaLinkQVMenu_CloseAll-QVMenu_CloseOtherFilesQVMenu_SaveAll)QVMenu_CloseFILENAMEDOCUMENT RCMu/AcWindows;component/QuickView/ControlPanelDictionary.xamlQVControlPanelQVPinButtonTT_QVD_CP_PIN%QVNewDrawingButtonTT_QVD_CP_NEW'QVOpenDrawingButtonTT_QVD_CP_OPENQVCloseButtonTT_QVD_CP_CLOSETT_QVD_CP_UNPIN _qnewNEW DOCUMENT _openQVDRAWINGPIN_QVDrawingCloseTT_QVL_CP_PIN#QVNewLayoutButtonTT_QVL_CP_NEW+QVPublishLayoutButton#TT_QVL_CP_PUBLISHTT_QVL_CP_CLOSETT_QVL_CP_UNPINBackgroundPlot_publishPUBLISH_layout _new NEW LAYOUT_QVLayoutCloseSMMenu_NewView3SMMenu_UpdateThumbnailForSMMenu_ThisView'SMMenu_ThisCategorySMMenu_AllSMMenu_MoveLeft!SMMenu_MoveRightSMMenu_RenameSMMenu_Delete#SMMenu_Properties_NEWSHOT)ShowMotion.UpdateAllOShowMotionQuickView.DeleteCategoryViewsEditShot ObjectName ViewFieldName name!NewlyCreatedName;Standard.InvalidNameEmptyName7Standard.InvalidNameTooLongSStandard.InvalidNameUnsupportedCharactersGSMRenameErrorTaskdialogTitleForViewOSMRenameErrorTaskdialogTitleForCategory?ShowMotionQuickView.RenameErrorTT_SM_CP_PINSMPlayButtonTT_SM_CP_PLAYSMStopButtonTT_SM_CP_STOPSMLoopButtonTT_SM_CP_LOOPSMNewViewButtonTT_SM_CP_NEWTT_SM_CP_CLOSETT_SM_CP_UNPIN!NAVSMOTIONCLOSE SHOWMOTIONPIN=../Resources/Images/SMPlay.ico?../Resources/Images/SMPause.icoTT_SM_CP_PAUSELeftButtonLeftImageRightButtonRightImageTT_SM_TN_PLAY9../Resources/Images/SMGo.icoTT_SM_TN_GOTT_SM_TN_PAUSE=../Resources/Images/SMLoop.pngTT_SM_CP_UNLOOPA../Resources/Images/SMUnloop.pngAACCIP_WAYPOINT_QUICKVIEW_CLICKED;ACCIP_STATE_QUICKVIEW_CLICKEDCACCIP_ATTRIBUTE_QUICKVIEW_CLICKED?ACCIP_WAYPOINT_QUICKVIEW_SCROLL9ACCIP_STATE_QUICKVIEW_SCROLLKACCIP_ATTRIBUTE_QUICKVIEW_SCROLL_MODETT_NoThumbnailTT_UpdateThumbsk/AcWindows;component/Resources/Images/DrawingSave.icom/AcWindows;component/Resources/Images/DrawingClose.icoTT_QVD_TN_SAVETT_QVD_TN_CLOSE#QV_DocumentsTitle[ACCIP_ATTRIBUTE_QUICKVIEW_OPENED_WINDOW_STATE_closeall .dwt .dxf .dws _qsave _close _plot PLOT=QV_BeditLayoutSwitchNotAllowed#_-layout _rename pack://application:,,,/AcWindows;component/Resources/Images/X_symbol.pngpack://application:,,,/AcWindows;component/Resources/Images/ModelThumb.pngpack://application:,,,/AcWindows;component/Resources/Images/LayoutThumb.pngTT_Model!TT_UnInitializedi/AcWindows;component/Resources/Images/LayoutPlot.icoo/AcWindows;component/Resources/Images/LayoutPublish.icoTT_QVL_TN_PLOT#TT_QVL_TN_PUBLISHLayout NameF2#.0000#A*ContextualTabSelectorRules.xaml%ROAMABLEROOTPREFIX=ContextualTabSelectorRules.dllIAutodesk.AutoCAD.Ribbon.TabEvaluator- rule = m_rules[{1}]; if (!ContainsAll(selectedTabs,rule.Tabs) && {0}()) selectedTabs.AddRange(rule.Tabs);Onew Rule("{0}","{1}",{2},"{3}",{4}){5} false trueusing {0}; [assembly:Autodesk.AutoCAD.Runtime.CommandClass(null)] [assembly:Autodesk.AutoCAD.Runtime.ExtensionApplication(null)] namespace Autodesk.AutoCAD.Ribbon { public class TabEvaluator : ITabEvaluator { Autodesk.AutoCAD.Windows.Data.Selection Selection { get { return Autodesk.AutoCAD.ApplicationServices.Application.UIBindings.Collections.Selection; } } Autodesk.AutoCAD.Windows.Data.CommandStack ActiveCommands { get { return Autodesk.AutoCAD.ApplicationServices.Application.UIBindings.ActiveCommands; } } Autodesk.AutoCAD.Windows.Data.ILookup<Autodesk.AutoCAD.Windows.Data.SystemVariable> SystemVariables { get { return Autodesk.AutoCAD.ApplicationServices.Application.UIBindings.SystemVariables; } } Rule[] m_rules; public System.Collections.Generic.IEnumerable<Rule> Rules { get { return m_rules; } } bool ContainsAll(System.Collections.Generic.ICollection<string> selectedTabs, System.Collections.Generic.List<string> tabs) { for (int i=0;i<tabs.Count;i++) if (!selectedTabs.Contains(tabs[i])) return false; return true; } bool {0}() {{ try {{ return {1}; }} catch {{ return false; }} }} public System.Collections.Generic.ICollection<string> Evaluate(Rule.TriggerCondition trigger) {{ System.Collections.Generic.List<string> selectedTabs = new System.Collections.Generic.List<string>(); Rule rule; {0} return selectedTabs; }} public TabEvaluator() {{ m_rules = new Rule[] {{ {1} }}; }} }} }} 9Error Compiling Expression: {0} CurrentDrawing____.mredo _.undo^C^C{0} {1} menuMacro MacroMenuMacroIdControlName ModuleaFailed to create control '{0}' in assembly '{1}'DWGCONVERT acadZeroDocQATNonZeroDocQATZeroDocAppMenu#NonZeroDocAppMenu#ZeroDocHelpButton)NonZeroDocHelpButton#APPFRAMERESOURCES\RibbonControls+AcRibbonCommandButton &#x0D; &#x0A;+RibbonPaletteSetTitle_RIBBONIB1AC3ED0-9573-4569-A97A-D9CAE382F5D2!RCDATA_16_RIBBONID_Help Ribbon PurpleRibbonRoot.cuiHeader.cui'RIBBONCONTEXTSELECT%RIBBONDOCKEDHEIGHTRIBBONSTATEe.ContextMenuERibbonMenuActivateToolPaletteGroup5RibbonMenuToolPaletteGroup#ToolPaletteSchemeRibbonMenuNone!RibbonMenuUndockRibbonMenuClose1_TpNavigate _group;{0};;_RibbonClose _cui %RibbonMenuAutoHideRibbonMenuTabs!RibbonMenuPanels/RibbonMenuAutoHide_None)RibbonMenuShowTitles'RibbonMenuCustomizeRibbonMenuHelp LOCKUI!CleanScreenState!CLEANSCREENSTATE_.RIBBONCLOSE _.RIBBON Alias SETVAR!RIBBONSELECTMODEID_MText_Tab;RibbonService_DynamicHelp_Tab?RibbonService_DynamicHelp_PanelERibbonService_DynamicHelp_DropDownRibbonItemIDG{0} {1} : {2} {3} : {4} : {5} : {6}expander;{0} {1} : {2} {3} : {4} : {5}/{0} {1} : {2} {3} : {4}#ID_RenderProgress^C{0}{1}{2}WSRibbonRootItem=__ID_RBN_'AcRibbonSplitButtonXYZPoint3dSourceStringTargetStringIsDependent Name$0$2$3$4$6$7$SF$SH$HC{0} {1} '_vsfaceopacity {0} STATUSBAR {0} VSSILHEDGES#_VSSILHEDGES {0} VSEDGEJITTER%_VSEDGEJITTER {0} VSEDGEOVERHANG)_VSEDGEOVERHANG {0} 9NumberOfObjectsOnLockedLayerONumberOfObjectsOnFrozenOrTurnedOffLayerG_chprop _color _COlorbook {0} {1} O_chprop _color _Truecolor {0},{1},{2} )_chprop _color {0} SourceTypeTargetType bModal Target SourceTextBoxTextIsReadOnly-QV_ShowMotion_Cat_Nonea/AcWindows;component/Resources/Images/SMPlay.ico]/AcWindows;component/Resources/Images/SMGo.icoCACCIP_WAYPOINT_SHOWMOTION_CLICKED=ACCIP_STATE_SHOWMOTION_CLICKED?ACCIP_ATTRIBUTE_SHOWMOTION_PARTPANEL_CLOSEPANEL_LOOP_ONPANEL_LOOP_OFFPANEL_STOPSEQUENCE_STOPSHOT_STOPPANEL_PAUSESEQUENCE_PAUSESHOT_PAUSEPANEL_RESUME_ALLPLAYPANEL_PLAYQVSMPREVIEWSIZE%QV_ShowMotionTitle_SEQUENCEPLAY SEQUENCE_PLAYSEQUENCE_RESUME#'_-view _restore #SEQUENCE_GO_THERE_VIEWPLAY SHOT_PLAYSHOT_RESUMESHOT_GO_THERE+Software\Autodesk\MC39DisplayUnexpectedCloseDialog'CIP.UnexpectedClose-CIP - Unexpected CloseCIP?HiddenMessagesSettingsDialogbox/AcWindows;component/taskdialog/hideabledialogsettingsdialog.xamlToolbarsyesToolTipsShowShortcutsShowCommandLineShowUserTagsShowExtendedExtendAfter2FixedProfileGeneral'ToolTipInitialDelay500TOOLTIPS1cAutodesk.AutoCAD.Windows.Resources.StringResourceY/AcWindows;component/Resources/Resource.xamlW/AcWindows;component/Ribbon/AcControls.xaml$$M=BasicContent HelpIdHelpPrefix]AcDialogToolTips;Component/DialogToolTips.xamlHelpContentShowHelp!ShowF1HelpString%BasicContentMarginIsEnabled TitleProperties LUPREC AUPREC:::TitleIsBoldTitleAlignmentPreviewPreviewSize/PreviewStretchDirectionDetailsShowPreviewShowDetailsShowSeparator#AdjustPreviewSize CVPORTBLOCKEDITORAPSTATETPSTATEDASHBOARDSTATEOPMSTATEQCSTATEERSTATE#LAYERMANAGERSTATESSMSTATEMSMSTATEADCSTATELIGHTLISTSTATEMATSTATEVSSTATE!RENDERPREFSSTATEDBCSTATEVSFACEOPACITYLIGHTINGUNITS_CreateDelegateʾL! <z\V418V6N5%)==1%--%  - -     %--- - % %   4 888 4 8  8  8(    ((0 , 4, , 0 0 ( ( (,(0(( D DD(D4 , , ,444 , ,"4 888!-4 88848884 8488 80 8 8( 80  (  %)%-     !% % ) )- !%) ) 1   5 1  9 =L AE EAL-T%-AL ) T  (IIIM` M`M1 M1 Q M`M1!U t t Y Y Y Y ]t(t(Y ae iY m U h  (     q u y !      y mE}( (     ((    e        (    eee?_ :e     ( H       H(H  <         d@@@@@     u         0 0              Y  (              ((( 1             $(    $( ,0!!Y %%! %)! %)! - -8 8 151(8 - 9 L  - -@L  LP- -- P-=1--X            | ||((|   x x x ( (x A| Ex (Ex xx  I M MQU YY(Y ]]=  aa ea a uui -% E  m% % Eq  q u y ! !}u%}u% - %q %um %% -% (% (Eq    %   ( ! }u            ( % % % % (%  -    - -& M M M M    %  %%    |  0   %)             1 1 1   % %4!MM(( (%    (    (      !- %M )! ) ) )   -1 59==9AEIMMI!QUYQ!YU]a e i !        mq q u u(u y  ae ae }Y\ d d d (d e e     a a(a  &CIP.UnexpectedClose,CIP - Unexpected CloseCIP*Software\Autodesk\MC38DisplayUnexpectedCloseDialog!!!!      % (  !  (  (    ( i ii(i a e eaY    e e  ((e(  q" ,((04       ae e e a        !   %%  ))   %  11 % -%11  -  u9A E == I  Y   -MYIQ EE aa e i* EMYaa MMaa1 m -MY1Maa aua q y } q y }  Pa%       #-1 -1      e %,8 m18 4 4888888181818 a      a }&aa 1%  #%1%aaa  E ! E% 8@D18a1, ,1,  ,     ,1, ,1, 0 0    a48(4888 aa!    y-a% )aa - 1= 5 9=9= a  I%- m E1 TT%)-11  M Q Y a )'%-!-IIQQIQ)-)aaa#11  M !  % e%!a!a! i %%!!IQa!A E%%!+ %!!!!uIQa %%IQ - ), --)1IQ) yy e y y%%-IQ !!!!)IQ%  )-a -  )A i  )  ) ))) ))Q $RibbonRibbonRibbonRibbon&Ribbon+Ribbon+RibbonRibbon   .Ribbon RibbonClose RibbonCloseRibbon0 QuickView QVDrawing QVDrawing QuickView: QuickViewQVDrawingCloseQVDrawingClose QuickView. QuickViewQVLayoutQVLayout QuickView8 QuickView QVLayoutClose QVLayoutClose QuickView4 NAVSMOTION NAVSMOTION NAVSMOTION NAVSMOTIONC NAVSMOTIONNAVSMOTIONCLOSENAVSMOTIONCLOSE NAVSMOTIONCLOSE  I  a  m  ) a  M` M1 lY   pa YY  pa Y YYY  !   pYp Y aa^Autodesk.AutoCAD.Colors.Color, acdbmgd, Version=18.0.0.0, Culture=neutral, PublicKeyToken=nulloSystem.Windows.Media.Color, PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35Yi iYii1    ! )i1Y%) -h  aa q= q A E I M Q EIMQ eAU qY ]  a! e i m Q ! y  ai_send_feedback}M MM MM M  U          QYY   a    1    @3System.Resources.Tools.StronglyTypedResourceBuilder2.0.0.0- -              ! %  ))mIQ8 11-1 I !Y      1  911   1= A =A  I  1 YYI aYI  YY1 M Q  I      I % I%YI    1I % e %  e   Y  aae-Y Y iu u  } q I-  --  ) % Y  %%- I -"%%%%%%% %@   %,    AiI1Q!!! !%-     -a a( -@I-IQ-@1- ]   ] % %= AAee   I -IQ- ---- %-- I-I I- P =-= 1   =    -1 a                   Content Rulesx% - Y159] Y    = = =%x1x x %xxx1x1   QE UBxxMEQY11IQ% %IQ1 a u]a ae--IQ m --IQ  IQ]= u  -yaeM M-  a-   a aIQ  a%q  m%q%q%uu  uqIQIQ u uu!!ua$ --a11 ! Q U Y%  i  iai L%iiiiIQaaIQaiIQ%  99 !8}%u!!IQ  5   M a ] !!IQ e   9 = !IQ E A-a-a a- -a-                        !% ) - %Exax% a11 fxxaaxa1ax1 %% y( -1IQ 9 = xAaxIQ E Q ! Y U.iIIQQaA >Aaaa aIQQeUQ Y5 ] a i    e`qaiIQaIQIaQaa } M I}u i1 mM Mq uu y#%%%%%Q%%IQ% %  U-  }}  }}} -- 1   ! % =]aaaaaaa!!Q !-  )2)qau!aIIQQ  !!IQIQ!IQ e111Oaaaa111aaaa - -1 59==9AEIMMI!QUQ!Y]ae E eu!  A E  y = 9aIQu    I I         ) )  Y  q   =}i)\d1d d1d      %-1% %   !           Y  %%    !     ! n.-! -IQIQ)$9BFE898D-8D59-4772-B140-FE86023C0100 1- !$--1 --%9 9 9    a!a %   = ===uMD@WJAutodesk.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator8.0.0.0EE aa!I  E=M ! Properties ) ) Y Yi)))) ]8U.Autodesk.AutoCAD.Internal.Windows.PropertyTypeaY a=8Autodesk.AutoCAD.Internal.Windows.RolloverColorConverter1' 1iquq (a}e }e }e }e  ProductionAutoCAD Windows Library. AcWindows % Autodesk.AutoCAD.Ribbon.Commands$Autodesk.AutoCAD.Windows.Module72Autodesk.AutoCAD.AcInfoCenterConn.AcInfoCenterConnTWrapNonExceptionThrows~*-+(; o< ,s*~*ow() o= *2() o> *Z(; ,*(-**( *{7*"}7*(x *~(&((' , (o *f((' , (o *~8,~8uS,~8o8*~8,~8u3,~8o8*(*~8,~8u,~8o8*2~8*{:*b{;( t};*b{;( t};*b{<( t}<*b{<( t}<*b{=( t}=*b{=( t}=*02Ju - r ps z{; ,o so *0K( {< , s o *0K( {= , s o *J~_, ~_o@**0r p( ( &*{d*~{`o - {`o {`*0'_{`o (p ,>skot*6( (W*0$h{i,*}ir'ps ( *N( (]([*0$h{l,*}lrps ( *( }m}n}o}p}q}s}u*( }m}n}o}p}q}t}u*( }m}n}o}r}u*{m*{n*{o*{p*{q*{r*{s*{u*{t*~v-sovs x~v*{w,{wol*~xo *0"k+~xo (q~xo 0*V( }}*{*{*r( }}}*{*{*{*j(&}}*{*{*}}( }}*{*{*( sz (W(_(]*( sz (W([(U(_(a(]*{*"}*{*{ *"} *{!*"}!*{"*"}"*{#*"}#*{$*"}$*{(*"}(*{)*"})*v( s  (js! }**{**{+*{,*"},*f(m s (n *f(p s (n *b{4( t}4*b{4( t}4*(y *:(y }7*(y (; , rIApsz z}5*{5*(( ,}5r]Ap({ *{6*(( ,}6riAp({ *{7*"}7*0&(| ui -*o((W *(} (~ -( -(W * *Z{7,{7*{6*( *0]( ,*ui ,o,(-*(o o .*(u -*o -**( *0[(o o  (o o  + (X i2s s ~Bo  (*0,-*s (*b{T( t}T*b{T( t}T*b{U( t}U*b{U( t}U*b{V( t}V*b{V( t}V*b{W( t}W*b{W( t}W*b{X( t}X*b{X( t}X*b{Y( t}Y*b{Y( t}Y*b{Z( t}Z*b{Z( t}Z*b{[( t}[*{\*0H(Y -*(Z 3*(Z 3*(Z 3*(Z @3**([ *"(\ *^(] ,*()(@*o< -o9 (), ()o= *{z*{{*f,oE -*oE (*,o , o oF -*o oF (*Z~( t*~*0X~(B ,Es.~,~~s o] ~o0(sS o'~*0V~-*o rIp(  (~-*~ ( ,*-(r (a&~ou *6-+G*s z0V_u -*o &o ( ,*o ( ~ ( ,*( (d&o *0V_u -*o &o ( ,*o ( ~ ( ,*( (d&o *0f-*uV ( ,*( *0$h{,*}r9Sps ( *~*~o 3 ~o ~o ~o8 *~o 3 ~o ~o ~o9 *2~o: *.~o; * *(| *F~o5 ti*6~o6 *F~o5 t *6~o6 *{*"}*{*"}*{*"}*0>(; ,*s ( o(; - s ooo*0=h-*oC (; ,* oB (; - oB s oC sQ *~*.( oY *2( o *.( oZ *2( o[ *{*"}*{*"}*.( o\ *2( o] *.( o^ *2( o_ *0<(rWps@ ( oB ~(v &ss (f *0$(   (L u ,}*2~(5 *6~(6 *F~(5 t *6~(6 *F~(5 t *6~(6 *F~(5 ti*6~(6 *F~(5 G*J~G(6 *F~(5 G*J~G(6 *J(s( *F~(5 t *6~(6 *F~(5 t*6~(6 *(7 *B(7 (*B(7 (*{*"}*{*>}}*{*"}*( *:( }*{*"}*{*"}*F~(5 t *6~(6 *F~(5 G*J~G(6 *F~(5 *J~(6 *F~(5 t;*6~(6 *F~(5 *J~(6 *F~(5 *J~(6 *F~(5 t *6~(6 *F~(5 G*J~G(6 *F~(5 G*J~G(6 *F~(5 G*J~G(6 *F~(5 G*J~G(6 *(*>}}*z}}}}*> 4( *2o *:o *0.o rZp $ o t*&o *( *(*(**0$(rpo# u  , ( o$ *0d( o% o&  ((' ,(o)o( ~- (( o% () ~~s)o* *( o 3*~,#( ( o! ~o" *( o 3#( ( o! ~o" *~-*~o 2( ~on ~( *0Z (# -*rp( o o rp( o o rp( o o *N*0:( o rp( t  rprp( ~ o *0(% . o u>**0) +o o (o ,*X o 2*0R-*-*o  +4  ($ - (' ,o o (&X i2*.s *s }( }}}}(h }*{*{*"}*:( }*J(?(@s=*{!*j{"- s }"{"*{#*"}#*{$*"}$*"}%*2{%_*2{%_*2{%_*{&*"}&*( *00 +"o o9(N, o  Y X o 2*0$; ?*o  o *0((; ,rp+ (; ,*rp(  *0V,rpo ,   o o?( -oD*o@(R,o@(S,oD*0D%-*o u5 , o (R*o u -*o  u (R*0\&o -*o u ,o u (R*o u -*o! (R-o" u (R**0F*o ,*o> (VoC3*oA(b r#p(o( o+ *0_+sK o? o (co? o oT o" o- o (Oo* o) (co* *0a+(` o- o 3(rOp(o (> o? rpo* +rqp(o (> o? *z,rpo ,   o *V(1 }'( *{'*02-s2 o3 rpG( ( (4 (*F~((5 G*J~(G(6 *0I( o )~)(m( ns o ( os o *( o 3~), )(m*j( o 3 )(m*09( o rp( t  rprp( ~ o *( o 1(9 -*rs (: (s(l*() *(voW (voX oD (vo oD *0'rprp( ( (; ,*( *0A8{2( -*s {2o ( (o ( }3*0:@{0,*u+ -*o -o rp(o , (*(v(A oM rpoN o Q.+o> *( o 3{1,((x}1*( o 3{1- (y}1*((|o (~(*0K((({rp}2o (~(vo o 0((*({3(; -{3rp( &*{3(; -{3rp( &*N( , ( o *N( , ( o *^(sC oD *o - ( }5*o 3}6*~**{0*"}0*{4*,**F*sz /*( *~8*03H~9( , r p( o s 9~9*B(r po *B(r po *:( }:*0>-s s o r pV( ( (4 >*01Lu ( uV o .o .o *{D*"}D*F~>(5 tV*6~>(6 *0/Ms o(; -o{D{?o  *0)Ms o(; -o{Do *0+Os o {B'o {Do *f{Do }?(*0+O( ( o t| ,o ( *0( .(*(*0F-s2 s$ &(% o& o r pV( ( (4 E*(*F~E(5 tV*6~E(6 *{F(; , (o' *{F*"}F*(( *0RtV ( Z*0$SZ (* (+ (, (% *{G*"}G*~(B oC 3(-(*(D ( G-(-(*0@(E u+ -*u*0%U( ,((F o(*( *"}K*{K*( *"}L*{L*"}M*{M*0Gr p ( %( (H Or pG( %( (H P*(I *b{N( t$}N*b{N( t$}N*F~O(5 t *6~O(6 *F~P(5 G*J~PG(6 *0PV(K ( #s (N {Q(Q {N,s o{No*(_ (` (O }Q( *r(a (b ,( (M *0Z(b -0oC  3 ( ( *oC . oC 3((*oC . oC [3( *(c *Z(b -((d *(e (f og r p(o -(f og r p(o ,( *{U*"}U*b{R( t#}R*b{R( t#}R*0#Yu& -*( u  ,o*0EZu& ,-*o7 o*o5 o**Z{\-*{\oJ *J~V(6 *F~V(5 *J~W(6 *F~W(5 *J~X(6 *F~X(5 *J~Y(6 *F~Y(5 *6~Z(6 *F~Z(5 t *6~[(6 *F~[(5 t;*R%(#(!X("*R%(#(!Y("*0%\oC 3{\oR ({ ,("*J{\(%oJ *0M( o 1(9 -*0s (: (/-*(; o< -*~_- s3_*2{coD*r6s (: (\(V*0^o ,}e( o *0;^( {do o {do -{e,}eo *R{d, {do *R{d, {do *0bb,0r p(u3 -*( o -*( *r p(u3 -*( o -* ( *.(< o} *j{f,{fs o *(B*(A*.( o *:( o *F( o s *0`e(< o} r% po Xo r po o ( (M,rprp( ( *~ * *07 ] YE YE+**uc, o /*( o o o *( { { { { { o *b{f( t}f*b{f( t}f*02(< r p(o % r p(  ( *0M YE+1tg}g*th}h{hUss o *}i*^{jo o ( &*0M YE&+1th}j{jZss o *tg}k*}l*03H~y( , rp/( o s y~y*~z*z*0l(vrtp~zo tk*{{*:(}}|*j({{{, {{o *01m{|o( o {{(&{|o*0Rns -G{|o( o (*{|o,(&}{{|o*s }}( }(*05o{}o t7 -*oo,( o (&*{}*{*"}*{*"}*F{o ( *0Eo oC .*{}-*{}o t7 -*o-o- {}o *n{},{}o  }}*o  ,2o  rp(  - {},{}{}o  o*{~,{~o{}~(}}*{},){}o t7,{}o t7o*R( o 3(*0-o{},${}o t7 ,o.o*0]o{}-*{}o t7 -*o,oo-({}o , {}o ( o (&*{},{}o  3 {}o! *,o" 3{}, {}o! *n{,{o (&*n{,{o (&*0@{o {},,({}{}o  o{}o! *"}*{*"}*^~- s~*0<s-*{}o t7 , o-*(o( .*(*{},1{}o tE,{}o tEo-(*0Et{}o t7 -*rp( Q.+ o3*oo*}(s}~(*0,p( s o6 {, {o*F~(5 *J~(6 *F~(5 *J~(6 *{*"}*{*"}*F~(5 '*~(5 '}~'(6 *{*"}*b{( t5}*01{( o: +oF ut, oF tt*o[ -*01|{-"(; t -*o< t7}{*0U~K (L {###s ( (-*{, {o*V}}(M *}}}}}(| ((*03\0 #*#s@Yl#X@ZX# @X *{*N{o{*R}{o*{*"}*{*{*0( ,o*0 {, (N , *"}*{*0U  (O  +2 oP (Q 1(Q (R /(R X i2}}*0)  {(,rpp(+ ,**0Uux ,JoE u? ,;oB,3({,${oE u? ,oX-(&*"(*0P(-*  tz(({(,{,s& {o5*0P(-*  tz(({(,{,s& {o5*04(-*  ty({(,(*0{,s& {o5*0P(t%(   (,*{,"oos* { o5*0?u% -*o; u -*o; u -*o; uy  (*0c,0#P@# @{lZX#?X#?X*#@@#UUUUUU?{lZX#?X#?X*0&\((Y#@Z (/ (U *&o*{ooq {oor 9*:{(+*02,%,"(+ ,o[ ,or 9*9*01,$o ,o o tx ,o\ *#*0'}  {(-*(*{X,&{Xo,{Xoo *((}}}}}}*0@\{-*{o {~oL {o}(*0Q{,*rp({(s> s@ oA o? {~oL }*{, {,{o! {o! *0<o o: o[ &oF uz ,oa (o ,*oF -*0`u4 ,Uo 2oo o tx (o 2 oo o tx(*0Urp(e t}{ss of {,{,{o {og &*{( #@##s o *0%o {,,{o og &*0/-*oE t? oXToYTJ2J/**07{o {ooS oT Y3 X(*09{o 0{ooS oT 1 Y(*06{2*{ ,oo o tx (&*0Z,V,<r p(+ ,,rp(e tom r,p(e ton rp(+ ,o! *0  v(o _0 w(o _1 *0V{o t -*os t -*,rtps s o *rps s o *b{( t=}*b{( t>}*0$h{,*}rps ( *0J 3<t7}{ ss of {%sx o *}*F~(5 G*J~G(6 *F~(5 t*6~(6 *F~(5 t *6~(6 *F~(5 G*J~G(6 *F~(5 t*6~(6 *F~(5 t*6~(6 *F~(5 t*6~(6 *F~(5 t *6~(6 *F~(5 G*J~G(6 *2~(5 *6~(6 *F~(5 t *6~(6 *F~(5 t *6~(6 *F~(5 *~(6 (H- (T(W*(T(Ho Y(W*F~(5 *J~(6 *{*{*V}}( *}}( }}*sZ*b{( t@}*( (f og rJp(o ,{,{s ob**.~o*Z(}o*{*"}*0B 3( o  +) 3 ( + 3( o (&*0Gty ,4o< t ,%o< tx {.{,((*(*0.  {(,rpp(+ ,o**"({*"({*"({*"({*"({*"({*"({*"({*"({*0-  {(,{,{o*,{r2p(o *{rRp(o *06m(-*( o (' ,(rRpr^p(*06m(-*( o (' ,(rxprp(*0P{}{({-rp+rp(rp{-+'(4 *0&m( o (' ,rprp(*>(o*{*"}*,{rp(o *{rp(o *0Wm(-*( o (' ,9rp( Q-(rprp(( o (&*06m(-*( o (' ,(rprp(*0P{}{({-rp+rp(rp{-+'(4 *0&m( o (' ,rprp(*0b}}s }( ( }}}}o(y}*0X{s o {(s o (~-(*( - s ( *0+( o (B ,*rp rp(*:{( &*:{( &*0/( rp( ( o o 3( &*:{( *:{( *:{( *:{( *0~,*rpp(+ o *6{( *05( rp( ( o o 3 {( *0F( o (B ,*( o (&r p{( rp(*0a(-*ty o< t o< txoE t? oJ}o<, oJ}((*0C(-*o 30( o , ( o! o }{o *6( o! *0Gs r( pr> po rH pr\ po rf po ( ( o &*~ oC . oC 3 {o*,{r<#p(o *{r("p(o *(-*{}{{o*V(-*{o*V(-*{o*0Hm(-*( o (B ,*{-rZ#po rprp(*{}{(r|#p{-+'(4 *2{o*{*{*"}*{*"}*:{o*>{o*{*"}*0L,>(  +/( ,u9,9*( + 9, *X 29*0.o# tz  ss ot o og &*01s o , ss o oS o &**(*08s o , ss o o oS o &*0N( o ,Ao 18( ( r%po ( r&po ( r<&po o *0N( o ,Ao 18( ( r&po ( r&po ( r&po o *{*"}*:( (*0Q{-*{s o {s o {o }}*B{-}*0,{(( {.}}*}*{*r{ ,{ o**Z{ , { o**}([(Oo -+(C(*0)m(Nu oH ((K(o*{ *0Is }(}}{s o {#Y@(/ o *{o-{o}{o *0D{ oD 7 +o uP,o tPoo[ -{ o *({} { , { o { -*(*0Rv(|{ -*{ o YE*{o*{o{o*0Y{ -*( { (# { 3} { o uP, tPo{ o *F{ oNt*.  *( *0@( !(l}(#@{ZX(v (u (*{*"}*{*"}*^~- s~*Zo/o.1(*0Ns-*{}o t7 , o-*(o( E *( *( *0;t{}o t7 -*rp( Q.+ oo*{},1{}o tB,{}o tBoj-(*0R{},{}o t7o,*({,!{~,{~tQo,}*{~,{~tQo o&(}}*j(s}~(*0+p(  s o   s o *0+p(  s o  s o6 *>}}*0N-*o' E ,*o)(*o)(*o)(&(*0;s o o  o . o 2 o + *0=/*( o 2*oE  + o[ &X 1oF t*0N( o ,Ao 18( ( r7po ( rpo ( r(po o *0m( (*09m( o (&( o (' ,r)prp(&*z(' ,r\)prp(&*0m( (*0P( ( (' ,8o o- 3 o o o (' ,o o ( *09m( o (' ,$rprp(&( o (&*0)m( o (' ,rj)prv)p(&*0#m( o (' ,r%po *07-*oD 7 +o oJ(o ,o *o[ -*0ds o r)p  E +r)p +ru*p +r +p s o  o o o *(*0 ( ('*0\ (B -o , o o ,o5 (( ()* ( o 1()('*0Ss r( pr,po rH pr\ po rf po ( ( -*o &(&* ( o , o1*o/*u ,t o2*o0* *0&\l {(; ,{( *(  *{*"}*0=(; , #W*o  (S (  O#x&?4**0[#2@[(  #@Z *(5*6r -p( *0 \(6&*0[ #@[ #2@( [*0 \(=&*(; , #W* (S (  *6r-p( *0 \(B&*0j( d( *0j( ( l*00( ( ( iYl( ( l*0j( t( *0j( ( ( l*0.( ( ( il( ( l*"}*"}+*Rr.p'o/ &*0ok ok(1 *f(R ws (S *0"(T -*( oD oS (x*0$o rp(o ,u -*(z*0&-* o u', o ' ([ *2u0,**b{.( t}.*b{.( t}.*j{.,{.~\ o] *0u0-*u0 -*(z*0Kr@pe( s^ /( ~/s_ s` sa (b *"of *~/*(g (h s (S s (i *(*2( oD *V(o s(W *V(o s(W *b{0( t}0*b{0( t}0*(*( }1}3{1s os s (? *0u -*(*{3*R(,(t *(u *(-(v +(w }2{1{2ox *J{1(o- *{8*{8(o ,*}8rAp({ *{9*{9(o ,*}9rAp({ *0+(, uj -*o(o(*6( ( *:( (Y&*( *r(y };(W ( *b{:( t}:*b{:( t}:*^{;, {;o **{;, {;o {:,{:s o] *BCs ( s ( *0@(; ,*r Bp(o ,(< o rBp(o ,*(R -(T **0Eo Y +5o u,#,o .Yo u,o Y /*04o Y +o t+(-o Y /(*0(r)Bpo# t  (*0"(r[Bpo# t7 o6 (*0"(ryBpo# t7 o6 (*0(rBpo# t  (*0(rBpo# t  (*07~C-*rBp( t  s C~Cs o ~C*no# (; ,*u0,**( }>}?}@}A*{?*{@*{A*Z{<-*{<o *0{<-*{<o &*0{=-*{=o &*0!(((s (*0,-*s (*-*{F- s }F{F{Fo *"}F*{F*2-*}F*0( -*o *0( -*o *0:(; ,*o,oo -**oo -**07 o ui ,'o u5 ,o oT o oU *0O-*ol ( -*u -*o o? o o (o o *0[-*ol ( -*u! -*ol o o o? o o (o o *04-*( -*uD,uD o (o *0A-*ol ( -*u -*ol o o< (o= *0$@-*ol ( -*ol o *{G*"}G*{H*"}H*( }K}L}J}M*( }K}L}I}M*{J*{I*{K*{L*{M*6( (*6o7 o*6o7 o*0(m( o (' ,o> o? (B **{N,*( s o  ( s o }N*{N-*( s o@ ( s oA }N*^~O- s O~O*vsB }PsC }Q(*0Fm{PoD 2*{PoE {PoF 3( o (' ,o*{PoG &{PoF /(*0d{QoK /T sL oM sL oN sL oO sL oP {QoQ *0N~ }irwCp(rCprCps^ (_ s` }\s}d{\oa *(Y -()( ,+o *j{e- s }e{e*{g*04 ()-*(; ,*{b-*{bo -*(;*()-*( ,( +( ( *0;$oc ()o  ( o (Y , (Z (o ( *0/%( t -* o -*( u -**0C&{h,*uA(B(A oM rDpoN o Q - ()o *0(9uX-9u-*9uX,9uXo +9uo   o , ooo( +\( (; - (; ,*(2o -*o -* ooo( -*s o o 9uX,9uXo (o o *~(A o o (; ,(<*o rDp(o ,(~(<*&(<*0)s {V, {Vo] *0]{\Hss o {\Ws o {\Ks o {\Ls o *0$*( rDpo -+hQo *f( o -*(M*( ()o  -()o  -(~*0Y-u -*o uA -*{c,5{co o ,o '. oX t +o*0S.u -*o uA -* {c,{co o (; ,*rFp(> (*"(o *.r3Fp(*.rOFp(*(U*( o ,( r/Dpo r/Dp( *{c-*{c()o{co(*{\-*(Y , (Z . (Z 3(x*0-0 +o o , %Y o X o 2*o1 ,{^-*}^*}^o< ,()-*}^*Z()-*()o *Z()-*()o *Z()-*()o *0J()-*()o -()()o o *()()o o **(y**(y*( o 3{],o }](y*( o 3o< ,o }](y**(y**(y**(y**(y*Z{m,*o (:*(),()o4 -}m*(4o (:*Z()-*()o *Z()-*()o *(>*(x*n{X-*{Xs o] *.(z*6({*(C *"(D *{y*"}y*V( }z}{*0!6uN -*~|oG &uF*.rGp|*:( }*v( o sH (I *v( o sH (J *0*8 +!uT ,oE u+ - (L -*ZrGp( Q.**r!Hp**~-*o .o- ~o *jo ~(,(*0<.ov 1 Xo .ov 1 Xo ( *2(*6(*Z~ ( ( (*0.B-*o| ~ ( ,*(} (d&*0C(~ (*0I(; ,* +0o &3!Xo / Xo &. o *X o 2*0(E  E +  +  + + *0*F  YE +  +  + + *0"G  YE+ + + *0!H  E+  + + *0I  ..+ + + *0(J  E +  +  + + *0"K _3` _3` _3` *0(L  E +  +  + + *0"M _3` _3` _3` *00N  E + + +  + + *0[O YE.*o: o *o: o *o: o *o: o *0rJp( (; ,*( *0-*( (; -( &*0Eoo o oo o oo o oo o *0aQo (; ,u-*o r7Jp( ,*o (u, s rGJp( o o *(*0Ss o ,+o *0:Us o o o o o (; , o o *0:Vs o o o o o (; , o o *0KWs o o o o o (; , o o o (o *0`Ys o o o (; - o o o ( - o o o ( - o o *b{( t}*b{( t}*0_t}{,Qt}{rJps o t}{rJps o t}{rJps o *F~(5 *J~(6 *0[( ( *( -((s (*0[( ( *( -((s (*0[( ( *( -((s (*rJp( }( s so (4 *F~(5 t *6~(6 *F~(5 t *6~(6 *0*\u~ ,oo( - oo*0*\u~ ,oo( - oo*f( s ( *{*"}*{*"}*0&Q *6oG*0EG ,((; - ((+-((; - ((( *(*{*"}*0&Q G*0\( #G*0+\(T r?Kp#Z(> (~ *0&Q .+G*0H&rp( Q - +3 +3 +3 rgKpQ(> (~ *0&Q G*0;arKp( Q  rKp-+'(> (~ *0GarKp( Q  rKp, ( e+( hQ(> (~ *0%cG ( , +G*0"cG ( ,+G*0J( ,i.G* +$~ ., G-G*X 2G*0GarLp( Q  rLp, ( e+( hQ(> (~ *(S*(*s*2tio*~ *0Fi uv,5v_ v0_ ,, + , +, *{*"}*( s (31s ( *{*"}*(6*0k(A od o , o *-rp*u, ( *o *0\o(  ,**( *0&lQ t  ( _ G*0UmraGp( -~ *( t ( G,`h +f_h raGpQ(4 ~ *2( *>'G*>'G*0&ou ,(L,Ms (? *, t(Q, t(Q( *2( o *,Ps o *Ps o *( *s z0\u~ 3~ *-*u ,o (ao (> (A od oe oR (~ *{*"}*0wt {( tXo *0wt {( tXo *F~(5 tX*6~(6 *F~(5 tX*6~(6 *F{o *F{o *Js }(7 *( *b{( t}*b{( t}*n{,{s o *2~(5 *6~(6 *(z*"({*0yu ,{, rMpoy*0yu oz3 rMpoy*0BrMp( Э( ~s sl sm (4 *(  *{*{(o ,*}rMp({ *{*v{3*}rNp({ *:(}}*^~- s~*0 o(t7 o{}o3 *0N(( o ,<( ( rOpo ( rKOpo ( rOpo rOpo *05{(tF o(  }}}}*0{(tF o*0V(( o ,C( ,8( ( rOpo ( rKOpo ( rOpo o *(*0*-*o( E *(*(*0Et{}o t7 -*r|#p( Q.+ o3*oo*2{}o *R(s}~*0b{o3 s4 (5 (  ( rRpo -3~ r5Rpo) raRp'o ( rRpo2 &*2rRp( *rs6 ~o7 (&*rss ( *rTpo  (o ,#(rTprTp( o (o o*2~o *2~o` *~rTpи( o s *0)h~-rJUps ( t~*0)h~-rUps ( t~*(rs (? 0s (? *0@s(a s(b (; o (c (d &( s oe *0As o(g -,( o ,( rspo oo( *b{( t}*b{( t}*j{,{s o] *( o ,( r/Dpo rp( *:( (*{*{*z{(; ,{(; **0J~ (; -3rUpo ,&(p ,#rVpo ,o ( +( *~*(s *Vs(r t*0u  (; - o 3**2~(5 *6~(6 *F~(5 *J~(6 *Z}}}*:( }*{*"}*b ( 3*( *0au  ,MrhWpo /*o s o tVs"Xo o&*( *0Q ( 37u s o#o t  rhWpo%(  *( *( *:( }*J{l#I@[*0S( ,( o (B ,*( o o5 (B ,*o ,*r~Xp( Q*&(A*NrXp( Q*NrXp( Q*NrXp( Q*NrXp( Q*NrXp( Q*NrXp( Q*NrYp( Q*NrYp( Q*Nr8Yp( Q*NrJYp( Q*Nr\Yp( Q*NrnYp( Q*NrYp( Q*NrYp( Q*NrYp( Q*NrYp( Q*0&rYp( Q *0(]&{l{ls *0&(^ i}( i}(^&*0 ~:( o ~( ( s o ( s o ( s o ( s o s ( ( s o ( s o (( s o ~,!( o! ~o" ((*0s+ (, -*o- +j(. o/ o0 , o/ o1 o2 o- +!(. o/ o0 ,  o/ o1 (3 - o4 (3 - o4 *I.ww0( ~- o5 ~, (+(~o6 (#(&~o7 o8 so9 o: rAp(~(; -~+ (< o= (> o? rKps@ (A oB o: oC rps@ (A oB o! oC *0/oD ( oE 8oF t sG oH oI oJ (K o? oJ ( (' , oL oM ,o4 oN -(rpo# uoM oJ (O oP oQ oR oJ (S ( oT oJ (S ( oU oJ (V  oW oX oY &oZ o[ :u,o4 *ALSj t0oD ~, ~o\ (] s^  o_ 80o` X% 1$sG  oa oI  oa (K o?  ob oc oJ (S ( oT oJ (S ( oU oa (d 9oe ,z oa (O oP oQ oR oa (V oW oX oY & oL oM oN -$(rpo# uoM + of oZ ,o4 o[ : ,o4 og ,+(h  si sj ~ok *ALD=V -Cp 0ol 8om t ~on ol +g om t oJ oJ (o ,HoQ oP op oR oq oX or os ot ou ov ow o[ - , o4 o[ :\ ,o4 *(s  0u ~,-*sx oy 8(z sG oa oI oa (O oP oQ oR oa (V  oW oX oY & o{ os o| ou o} ow  oZ ,o4 (~ :[o4 o ,~  so &*(B@0  0 ~, ~o\ ( o5 on ol +fom t (] o_ +9 o` oa oJ (o ,o o  ,o4 o[ - , o4 o[ - ,o4 *(K#n ?E &r 0 (# -*rpo ,,u ,$( ( u ( o rpo ,,u ,$( ( u ( o rpo ,,u ,$( ( u ( o *0> (] o_ +o` oa (o , o[ - ,o4 ** %0 0< r=p( rKp( -+  ~o , *~ o ,t~ o ,f~ o o ~ ( ,E~ o ,3rYpo ,!~ o ,~ o o (; ,( rqp( ,o   .'Xo   ( , o  ( rp(    -a~ ((! ,:~o - ~ o ~o - ~ o ݸ&   (( (0( rp( (1^(q((!(q((!, ~o , ~o ~o , &**-V400~ ( ,* ( ( ( (&&*+0~ (o ,*(d ,> o ,o ,o s ( +( , &rpo 9,o o Y2* o  Xo ( -*~ ~  (~ ( ,,   s    (1  o  &~ ( ,(&, ** *(;UEJ0V-*-*~ ~ ~ ~ ~ ~ ~ ~ ~  ~  ~  o   rpo   , u   rpo   , u   r+po   , u   r7po   ,  u  rKpo   ,  u  rUpo   ,  u  repo   ,  u  rspo   ,  u  rpo   ,  u   rpo   ,  u   rpo   ,  u   o i-~ (o ,*s o ~ ( , s s oU &("  u o? o -o? o (; - ("o o o  ("  u o o - o  (; - s o  o o ~ ( , o i1o ~ ( ,"(%3 oZ +Co +8~ ( ,$(%3 oZ +Xo +oZ ~ ( ,Mo (%2:rp(o ,Xs o +rp(o , s o *10(L o@(Mo@o -*s s s {,  (+{,  (,{,%{ /s1o & (-{,  (.{ 0s5o &{ 0s5o &{ 0s5 o &o +( o ( -o4 o +( o ( -o4 o  + ( o  ( - o4 *( #AWu0Wrp( rp {o ol + om o -(Z o[ - , o4 *"*L 0Wrp( rp {o6 ol + om o -(Z o[ - , o4 *"*L 0{o o 8( o :r%p(o (> o o 8o o :o o rp(^o o o o ol +!om o - (Zo[ - ,o4 o[ :m ,o4 ( :o4 *(. M 0h{o +@( o o +( (]( -o4 ( -o4 *"@ MY0{o ( , ( o -*s ( ,J( o( o +$ o o ,o , o o & o[ - , o4 (o={o +0o o ,o o ,{o o o[ - ,o4 *<0l = 0o 8( o :o u ,'o u5 ,o oT o oU o -Po u,(rIpo# u;oT +'o u-(rmpo# u;oT o u,.o u  ogo oT  ogo oU o u#,lo -Vo ol  +/ om o ,o ,u- o +  o[ -  , o4 o o o u,#sk~(o ( &oJ( :go4 *A4<M 0`}$( }!s }"o +( {"o9s<o ( -!o4 *&+Q0ms   +8Xo ( ,$,o s<o X  + X +X Xo 2,o s<o s=*0 rp rpo  - rp(  +]o ?. o *3CYo  (  ( o ?3.;( + rp( X X o 2*0(; ,*;?*o o o Yo (P rpo  -;*o  o ( +3o 2 -/o .%o YY( ,o o -o *0O (; ,* o +( o9(Q, o; ( -!o4 *,?0:!o +( o:- ( -!o4 **!(0"o ,rpo ,   o u(d o?( ,o?( -oD*o@(R-o@(R,o@(S,oD*o o@(R& uo@(W,` uo@(X,` o@(Y,` o@(S,oDoB*0# o o@(R&o o@(R&o ,o o@(R,` o ,8o o o@(R,` o o o@(R,` o@(S,oDoB*0r$-*o u (R,*ui -*o u5 , o (R*o , o u-*o u o (R*0{'o ,*u8,ju8 o# (; ,o +o# rp(o$ , +rp((> (O o  ([*u0,{u0u>,o% , o& ,(\o# (; , o +o# (Oo ([*u,to' ([*u,t(\*u*-uC-uD-uE,o o (^*0>(ol + om o -(Zo[ - ,o4 *,3 0)o> (ToC3*oA(_ oC YEX,*rp(o( o) (Oo* o+ *r#p(o( o) (Oo* o+ *o( o+ *0)o> (UoC3* u,oC(a + (` oC YE,*rp(o( o) (Oo* o+ *o( o+ *0m+sK o, o (co? o# (; ,o +o# (Oo* o) (co* o o" oE*0,rp(o (> o rp(` sfo o* o- oEo ,]o (o o o. (; -o o. s o o o/ (; -o o/ o *0%-~ *o u5 ,&o ,o o0 (; - o o0 *o , o u-~ *o u o (; -o *~ *0k.(8 o oD -(+( ol +om (8 o oZ o[ - ,o4 -(8 o (p(&*&#I 0( s o ( s o s (? s ( ( s o s (@ s (A ( o 1(y}1+(x((B ,s (*(sC oD *0/({+,@{+oD  +{+(vo o oZ X (vo o 2({{,-?sx },(ol + om {,oZ o[ - , o4 {,ol +om (voE o[ - ,o4 (voF *s  0k0({,,@{,oD  +{,(vo o oZ X (vo o 2({{+:sx }+( s o ( sG oH ( sI oJ (|(z(vo sK oL (A oM rpoN sO oP +X{+ol +6om ~/o oQ , (voE +(vo oZ o[ - ,o4 (v(oF (*BI 0o}4rp(R ,%(v(rpo# uoS }4rCp(T ,*(vrCp( QoU (voV *01{-- s}-{-oY {.- sZ }.{.o[ (({rp}2(, , o\ 0*s s o-  +s (.  o] -+ o] 3 {.(} o2 o-  + (. {.(} (3 -  o4  (3 -  o4 , {-o, {-o{-o(,Go^ ,+}5{.o_ o` ,(o_ }2}6+"rSp( t (; -(~(vo o 0(*%{02oa ob  rgprpsc -*od oe o/ s of og oh 8oF tI sx oi oj >oi oh  +` oF tH(,ok o + ol (,ol o ,o" oZ  o[ - u  , o4 od ok (m on o[ :)u  , o4 ,Qoo oh  +" oF tKop oq or  o[ - u  , o4 *(m_=b/03(; ,*{-,{-os 0*{-ot -*-*ou ov (m {.o` &-*(ow (}5}2}6*0K4-*(({~/ox 0O(ol +*om ~/o oQ -~/o oy o[ - ,o4 sz ol +Qom ~/o oQ , (voE +(vo oZ o oQ - o oy o[ - ,o4 &(ol +4om  o oQ - o" (v oE  o oy o[ - ,o4 (*4*7a {^ st1A7 0d((vo ol +=om o (u,),sO o{ +sO o| o[ - ,o4 *IY 05(; ,*(, , o\ 0* o- +a(. ob ( - +Oo2 o- +(. ob ( - + (3 - o4 - (3 - o4 *R(z(n06Q-*s} o~ 1 rpo &rp(o &o of s o (vo ol ++om o , (, oi o o[ - ,o4 rp( ok Qof og o of o *`8 07-* of og oh + oF tI ok ( - + o[ -u,o4 -*( -*oi o o +o o oi o o[ - ,o4 of o *-F( 09-*s oi oh +6oF tH ok (; -ok o + ol o o[ -u,o4 s (vo ol +Fom o ,6 o o , o +s  o o o o[ - ,o4 *C[S 0:(; ,*( ( -*oa ob  rgpsc -* of og oh +$oF tIok ( -+ o[ -u,o4 *b10;rSp( t  (; ,*(, , o\ 0* o-  + (. o] 3 +  (3 -  o4 -*oa ob    rgp rp sc -*o -Too oh  +$ oF tKop ( -+  o[ - u  , o4 o - o] ,-,, o (u-,o (u,*(*(-*s o o o of o od (&o &*6"X10w<s o o (vo -+o o {-op o ,{-op o &{-op or (m }2*0={2(; ,(*{2( ( -* ^( ,7( ob o ( ~ ( ,*( tE -*oa ob s o -o] - (* of og oh  +$ oF tIok ( -+  o[ - u  , o4 -* (& of o ,( - o &+( , ( o {+oD {.{2o` &,oD +<(vo o   o ,{+ oZ ,  oZ X(vo o 2*10!> EP8-*( -*2"oi oj /oi o 8oi o 8( -*-*o  ~/oQ , oi oh +9oF tH ,ol (o , +ok (o , + o[ -u,o4 -*oi o of o *F0? EOq*u,#( r+p( ( o o &*( rqp( ( o o &*( rp( ( o o &*0ZAsx (ol ++ om o ,o o o" oZ o[ - , o4 (*7H 0Bo -*  {2(; -j{2( (,|oa ob  rgpsc ,N (-* od o &+.o o (&(; ,* o od (; ,*o (( (o *0((' ,q(o< ,W(o*--{5( ..{6,&{5( ( }5+( 3( {6,}6*( 3( *0xC(,*  o , o o 1o o u+ o , o o 1o o u+ o o o (*0?Do +( ( ( ( ( -)o4 *)00Es ( +( ( -( o &( -)o4 o +o ( &o -u,o4 * ,9Ol0F( o o (o o .*(&((' , (o (o) o o -rp(( o * o *0Grp( Q 3!rp( ( o o o *~8,~8(.~8o8~8- (8~8o- ~8o( o ,<( ( r?po ( rpo ( rpo r%po *0~8,~8(.~8o8~8- (8~8o- ~8o( o ,<( ( r7po ( rpo ( rpo r%po *0~8,~8(.~8o8~8- (8~8o- ~8o( o ,<( ( rpo ( r po ( rK po r po *0I( ( ( (rU po# uq o +#o  ,( o to o[ - ,o4 s ( o o s ( ( ( #?s o *10a 0 }A}B }C( s}D((r po# tx( {D( s ( ( s o  ( s o ( s o  *0YN{Do  +3 o  u,$u o( ,{Do  o[ - , o4 ** ?K 0EP {C( r? p((( {A( (( {@(  (rI p( ( (rQ p( ( (r_ p( ( (rk p( ( (ru p( ( (r p( ( (r p( ( ({Do }?r p((*0Qo o 0*o o u| 9o '{B3no o u s o (  ,4o! (3rp((+(+, o((" u,!(o(# , o(*04T(- o. ,o/ o0 o1 (2 8o3 , (2 8o4 , (2 8o5 9(6 (' ,g (% o7 o8 o9 o: to; ,o4 o< , o4 ( +B (2 ++o= ,#o> (? (@ (A (2 * 2 0V(-*(}S((J (K (L &(M #?s (N (O }Q(P (Q {N,s o{No*0W ((J (R o +d(R o r p( (S (T (U (V (W (X sY (Z ([ s\ o] (^ 1Y /(R o //2+(R Yo (J (R r p( (J *0X{T,*}T{S(R ( ,3{R,+s {So(R o{Ro(-( +(b ,( (M }U}T*0m~h &( &( si oj r pИ( &( #sk (4 Vr pИ( &( #sk (4 Wr% pИ( &( #sl sm (4 Yr1 pИ( &( #sk (4 XrKp ( &( ~ s sn (4 Zr+p;( &( so (4 [*0![(p (q rE por u_}]{],@{](ss ot {]{](u #@[% ov ow (q r_ por u_}^{^,@{^)ss ot {^{^(u #@[% ov ow (q r} por u}\{\,.{\*sx oy {\+ss oz *0^] (< o} ~ r p( o - +%r po , u', ', + ,o4 *$.R 0^( sS}c{coE}a(7{d,_( }`{`{cNs o {`{cOs o {`{cPs o ( { 1 { (=( 5s o s }b{b4s o {bs o {bo 6s (? *0#_(p ,or& {bo *1 0`( -( {c( ( }d( ( o <s } =s } {d;s o {d8s o (p >skos( - ( ( *0ra{`,-*oi,${`obocodogo *oj9oeof(? s s ( tT o -u,uu o o us o ##@##@s o ojo o o {`obocodo W&Toeofoh( - oho +(?-*{`obocodo *C10ca(< o} (< o (< o } } } r po Xo } r p r% po Xo ( o  r p( ( r p( r po o ( r p( ~ o r) prp(Ct } rC prp(Ct } rU prp(Ct } rm p(Ct o R( -R;(  (  } (< o= } *0bd , ,o  , o - 9u  - , ( #o ( o . ,o *PR0hfo ,_o s ( r} po o r po ,r po o + o (; &o ( *0g(< o} ~ o rpo ,u', ',ݫ ~ r-p( o ,+rKpo u ,rgp( + ,o4 -Orsp(rp(rp((   - sTo ,o4 *V1  0i(< o} ~ o ~ o ~ ,- rp 8xrp'o '/ rp 8Prpo - rp 8&r(po - rp 8rDp~ o t rVp(o ,rVpo t  8rrp(o ,rrpo t  8r~p(o ,r~po t  +xrp(o ,rpo t  +Vrp(o ,rpo t  +4rp(o ,rpo t  +rpo t  ,o4 ,o4 {j s o ,o4 ,o4 *Ad  o7 #  0j(< o} ~ o rpo rp'o ' 0rp'o ݏrp(r4p(rhp( 20rp'o ( o , ( o ( -*sYo ,o4 ,o4 *%  b{w( t-}w*b{w( t-}w*0"({s}}{}o {}o {}o {}o {}( oQ {}s o {}%s o {}%s o {}%s o {}s o {}sx o {}s o {}s }{( o o *0`o{}-*{}o t7 -*o,9o-1{}o ,$o-( o (& &o*CU0p%s ( s ( %s (? ( %s o ( s o ( s o {s o s ( s ( s }{s o {s o *0p%s (# s ($ %s (: ( %s o% ( s o& ( s o' {s o( s () s (* {s o+ {s o, }*0{},|( o- 3 {}o! *{o. -?{}o  .1{#@@(/ o {o {}o! *{o {o *0q{}9{}o t79{}o t7o-~{}o -q{}o0 o1 +# oF t s ( o o o[ - u,o4 ( o (&{}o  *W/0q{},{}o t7o,*({~, {~o|{-{,{{((}}*0r({}9rp( Q {~%zs0s s4o{}o {}rp(o2 {}o3 (o-rp+rp(*0Ko{},){}o t7 ,rpo'(4 &((*330u(o  9o  rp(  -u{},m{}o tE,[{}o tE rp( Q.+ o.*oo-{,{o (&*0v{o YE +}+}}({-{,,{~,${~t1{o}}{o*0Cw( s o  o o5 & (' , s}*(0\x}}}{,{o}o7  o5 & (' , s}*8 A0y{~,-*o' E"(K*{~t1o~o)((*(*{~t1o~o)((* u:,u: {}o t7 ,5{~t1o~ {o o)o+o,("&*b{( t5}*0lz(8 (f ~3&{,{{(so*(f ~3"( -*(+ -*(o9 *0}{,{s o= s> }o? s@ oA s oB ( -*oC t5 -*oD +(E ~oF (G -7o4 }*t!0Z~( -*oC t5 oD + (E ~oF {oU(G -7o4 *-K0{,{s o= sH }o? ###s sI oJ s oB ~K (L (*0jr&pИ( 4( (H r>pИ( 4( (H rXp'( 4( (H *0}}}}}(| (}{o1}} {oD +((E (oUoB,}X (G -7o4 d4}(e(#(*^50  {(-*/*{o -*oS oT +[o o tx,=oE u?,+2,(oC+(oCX 2}*0{(,*,7({( ###s o  8$90+{Yo  {%Y o1 - {Y{YoYo-/# {3 ( +{o( oD +(E  oU(G -7o4 ,{oo ,G( {o{###s o X {?*0q-*o; u -Uo; u -Ao; uy --o< t - o< tx&*ch0f-*o; u - Lo; u - 9o; uy - &o; u - o; uy & *Z_0A-*o< t -+o< tx {3&}o**.0v oE t? ,co<,[( {Xo1 oD +(E (oU(G -7o4 oo *8"Z0,:oV oW (X {,{(Y ,*}}{-(-*ty ,.o< t ,o< tx { .  (-*(*0   (-*  + .{ o- X {2 {3 {o{o 2 .{ o{}{:`{, s-{o9 >0(9%{X}{{Y{{Yo{o o {Y( {{Yo###s o 1g}({ (o{  ( o{(o{( o}(}8  <+M{{Yoo {{Y{{Yo%{Y}{YX0{{Yo}( {( o{(  o{X( o{XX(  o{,{(+{-({(*0u4 o/{o0*(-*}oZ 1 o(*o(*oZ 1{2*%{X}+!oZ /{0*%{Y}#y@(/ (U  +N}o. ( +( { o( {oX {2*0O ty ,<o; t ,-o; ty , o< t, o< tx &*HJ0(-*u4}{,B{o}{{o}{,{(+}{rp( }{rp( }*0o{,){,!{,{,{, {3:({,){,!{,{,{, {3*{(#@[ {o] (^ 4S{o_ #.5{o_ #@@Z #(/ (U (8(+|(^ {o\ Y6`{o_ {o` 4@{o` {o_ Y#@@Z {o` (/ (U (+(+((*0x{X9{Xo9{Xo1 -*oD +(E (oU(G -7o4 {Xoo X(  {Xo{X###s o *{( 9%{X}{{Y {{Yo{o  o {Y( {{Yo ###s o *?"a0z{,q{,i{,a{o_ #6{o! + {o! {o_ {o` 4 {o! *{o! *0( ob (^ {lYoc (d #@[X#$@X {o\ #@[X {o\ #@[Y {{Yl7{l{o\ Y {l5{l *0  # # # ( {.{o, -Kob   (^ {lYoc   (d #@[X#$@X ( 8?( #, (+d{Yo,5{--{Yo, (+,o_ }{Yo({Yo{Yol#?X# @XZX{YoXl# @ZX Y {ooS oT l# @XZXl# @ZX  #@[X  #@[Y  {{Yl7{{Yl Y  #5 #  *0\{,*}(q rpor u}(((q rpor u4}{ so{{{{o(  {o{###s o *0s {or:p(e txo  sosh rbp(e txo r~p(e txoi rp(e toj o og &sk rpol rp(e txo o og &sk rpol rp(e txo o og &*0(-*(,*oC .(oC .oC .oC . oC .*}u4 o?oC 3oX(*oC 31o>{oYo oY(*oC 3 o(*oC 3 o(*oC 3$oo(oo(*0f,b{,oL &r p(+ ,,r&p(e tom rtp(e ton rp(+ ,o! *0u% -*o; u op (q op (r X ,Lo; u ,=o-}#ow *o3} o\ Yow *0{-*ut -݆ +{o. X {2{Y. {3OX(  {Xo{X###s o &* b{( t=}*b{( t>}*0  YE6~*st ~u ov sw ox txoy oz *ty%s{ o| ty%s o tys o} *ty%s{ o~ *tz%ss ot *tz%ss ot *st ~ ov ss ox txoy oz *b{( t@}*0rXpG( ?( (H r+pЀ( ?( (H rjp ( ?( (H rJpG( ?( (H rpЁ( ?( (H rpЁ( ?( (H rpЁ( ?( (H rp ( ?( (H rpG( ?( (H rp( ?( (H r2p ( ?( (H rVp ( ?( (H r|pИ( ?( (H rpИ( ?( (H *0-(N -*(   (-*ty(-{o(p8@oE t? oNu(B -o ,o o -* oY-(( ,1rp(rp( ( o o o *rp((; ts (kls s o o &(k(*0o - s o o oS o ( o &&o r p( rp(rss (&rLp(sss (&rxp(tss (&rp(uss (&o rp(vss (&o oS s o &o rp(wss (&o rp(xss .+(&o rDp(yss (&o oS s o &(q o rbp(rp(  zss (&rp(*0rps ( u 9rpo# ty os u r:pss (}{,{rRp(o rnp~ss ( , rp(o rpss ( , rp(o rpss ( , rp(o **0(N -*(   (-*ty(oE t? ( o (B -o ,o o -* oY-(( ,)rp(rp( o o *rp((; ts (s s o o &((*0rps ( u 9rpo# ty os u r:pss (}{,{rp(o rpss ( , rp(o rpss ( , rFp(o rpss ( , rjp(o **0L( - s ( s r:p(o ss o ( oS o &s rXp(o ( oS o &s rp(o ss o oS o &o s rp(o ss o oS o &s rp(o ss o oS o &s rp(o ss o ( oS o &s r p(o ss o ( oS o &s r,p(o ss o ( oS o &s rHp(o ss o ( oS o &s rdp(o ss o ( oS o &o }*0{o {3g~-`( o (B ,*  {(,F3B( o (&r p{(  rp(*{3(*0F{2(N -*( - s ( ( &( -, ( o! *(}{-*{oE t?-*oJ}{(9( o! ( oS o u( oS o u - o +o {ooS oT Y3  o + o {3*}:( oS o u  oS o u  o  oS o u  o ss o ss o  ss o  ss o ( oS o u  ss o  ss o ( oS o u  o 8@( oS o u  oS o u  o  oS o u  o ss o ss o  ss o  ss o ( oS o u  ss o  ss o ( oS o u  o (*0-*u% oo( 9d  {(9K3oo o -r po(*oo o 1r po(*o ;%( o .r po(* rP!p(- r!p({oE t?, ooKoo oo( ,fo( s r( po ( r!p( ( o o  3ooo*0rps ( u 9mrpo# ty s o os u r:pss (}{,{r("p(o rB"pss (}{,{r\"p(o rx"pss ( , r"p(o r"pss (}{,{r"p(o ~-,r"pss ( , r#p(o rpss ( , r#p(o **0O( 9:{o tos t 3.r#ps s o {r\"p(o +],.r#ps s o {r\"p(o +,r#ps s o {r$p(o r4$p(+s rJ$p(+ r^$p(+ s  rv$p(+  9U { (9: : @{(o 9,U r#ps s o r$p(o  r$ps s o  r$p(o 8 r#ps s o r$p(o  r$ps s o  r$p(o 8n r#ps s o r$p(o  r$ps s o  r$p(o 8 @ :{(o 9,U r#ps s o r$p(o  r$ps s o  r$p(o 8 r#ps s o r$p(o  r$ps s o  r$p(o +P r#ps s o r$p(o  r$ps s o  r$p(o o   o {9.:{ooC o 8oF t?oJ(o ,`{o1oD +(E oToU(G -7o4 {oo + o[ :su,o4 *$90x{o t os t ,,r%ps s o {rV%p(o *rv%ps s o {r"p(o *0Orp o ,o o -r%p rp(  o &o 1(*.<07r%p rp(  (N ,( &o 1(*$0(B ,*{,{o }}{((}o s }{o {s o {s o *0Sx(Nu-*(Nu  o5 & (B ,*s o s} * %0Zx{ , { o(Nu-*(Nu  o5 & (B ,*s o */ 80(Nt o5 o ,(%(?(>o +0($(?rF'p(rprd'p((  (A &(?( -}{ , { o* Zf 0s ( : oE  +5 oF t oH rp(o - oH , %X ( o[ - u  , o4 { ,(} {o:{o8@o 0*{ oD 7+o[ &X1oF uP,oF uP-s z{ ,.{ 3${ o-{ o- { n{o {o } { oNu{o(*{o&{o } **B^ٗu0m{ ,{ -*{ oNu (B -o , o o -*{,;{ o,{ o- { o{ (&}*( , { o*{o{ oD +6(E uP,&uP { .o-o,o(G -7o4 { ,R{ o,{ o+ , { o{ { o(& - { o{o*C0qs oH (oKo5 o ,(%o?+0($o?rF'p(rprd'p((  oAo>, o>o &o=oMoOs o r'ps o o oEs o r'ps o o oGr^(p(oQr|(p(oS( o  o s ( o s o jo &o o oIo (&*b}0( ( ,P (O i1:+. oP (Q 1 oP (Q X i2l( ,qo oc   ( rp( Q- #ob   ( oc   ( XX# @X{XY( *0({}9rp( Q {~%zs0ssi s4os8o!{}o {}r(p(o2 {}o3 (o-rp+rp(*0{}o t7 , o-*( E  "-4:AG*( o *( o *( o *( o *(*(*(*(*(*0Ko{},){}o t7 ,rpo'(4 &(( *330(rp( Q 3(*o  9o  rp(  -u{},m{}o tB,[{}o tB rp( Q.+ o.*oo-{,{o (&*0{~,-*{~tQo o' E-*o)((*(*o)((* u:,?u: {}o t7 ,${o o)o+o,("&*0=( oE +oF t (o[ -u , o4 * +09 r%p rp(  o & o 1(*#0o5 o o ,o5 o +oH o -*s o r0)p(o -$o r:)p(o -o rD)p(o ,( o (&(' ,rN)prp(&*0?( o 0&o 0-*( o Ys  + ((' ,o X o 2( ~ ( o .  3* 38o  -  o +m o -N o , o o -'( o (& r\)prp(&+&  oH o +( ~ ( o &Xo ?i&&*8;0A( o5 o s o o -*( ~ o ( &*&=0>oD 7  + o[ &X 1oF t?oNu (' 9o o- 3 o o ( o 9o o 9 o (' , o ( ,)r)p(rp( o o {oF t?oJ-go ( ( oF t?oJo (  ,o4 &%( o (' ,o o ( *(' ||0 o o -~ (, 8o o 1~ (, +x ;%( o .~ (, +MoD 7  +4o[ &oF t?oJ( -~ (, + X o 2*0(! ,yoD 7  + o[ &X 1oF t?oNu (' ,;r)poF t?oJrp(  rp(&& *L60oD 8(E o oKo - ( oKo (%o?o>-|o -($o?+ ($o?o -r+p(oA+Ro ,r+p(oA+8rF'p(rprd'p((  oA+oAo>o &o - oM+oMo , (G :* 0_(B ,* o7 o o o: u o ,o4 o< ,o4 &*(*: 0L MZ0 8s[ +sao]o=oOoCs o r+ps o o oEs o rC,ps o o oGr,p(oQr,p(oSo X ?K*0u? 9oNu (' 9o5 o7 o8  o o: uo  +L o  ( o: t( oJo -oB, o +o  o -  , o4 ,o4 ,o4 *(\Y Jy ; 02#  (; -(  & - ~  ** 0 #@@ #j@6#@ 8#x&?4 # +n#.@4# 0B? #x&?Y[ +H#.@7#i@5#$@Z +"#33333h@ #@@#i@Y [X *0z#I@ #b@4# 0B? #x&?ZX +H#b@7#@@5#$@[ +"#33333h@ #i@#@@YZX *0E(; , #W*o ( WO(>W&#W **110(7 ( &rp * 10#?4#O贁N{? [ #?X +W#?7$#@@5#b@#\(\?ZX +'( #@Y#D@Z#@X *0{\#b@5#{Gz?Z +_#b@6$#@5#b@Y#^z?Z +/#$@#@Y#D@[l#@X( *0(" o# r#-p($ re-p( t r-p( #?( (% ,6(& +(&  (' , Xi2& (' ,Sis( +5() (* tao+ ,o4 Xi2(s(, (-   r-po. tb*Q3 0grB/p oZoTo^-r/p+r/po`o\'-rp+rpo0 &*0~--us2 -~-o3 s4  +Go5 oio6 +(7 oZo8 (9 -Co4 X o: 2o; ^ o< o= *@"b0s>  +Yo5 oho? +'(@ oc(; -r/pocoA &(B -Eo4 X o: 2r/po &(r s> s> +G oZrW;poXo/ &(p iY(qX i2r<po o o/ &sC  sD   oE ( o oF o & oE ( o oF o & oE (G oF o & oE ( o oF o & oE г( o oF o & +j o5 oho? +5(@   oe(; - oE  oe(H oF o &(B -Eo4  X  o: 2 oI  oJ  oK  oL    o oM   oN oO ,}s> r@po & oN oh +"oF tr@poP oA &o[ -u,o4 r@po ( sQ z*(4QB/0o 8 oF u9t oS oT 1oS (x8oU ,s1 + sV oW oX u (o? oY oZ o o o ysO o{ ( oZ +u,( s oZ o[ :3 u,o4 *0( o (B -oH oc od ,*( oe -*oE +6 oF t oH oc t0o od , ( o + o[ - u,o4 *>B0( oD ( ( o oE 8oF t sV oH o oH rApr Apoj  o? ok (oW o oH o (' ,oH oH ol , oZ ( oZ o[ :]u,o4 *$0{2,{2oq 0( {1u+or o +oF t &X o[ -u , o4 18(-rAp+r!Ap r/Ap'( ( o ( {0,{0s o] *5Q0((; ,*( o (B ,* ((' ,7(o),+(o)o , o , o o ((( {4,{4s o] *0~ ((; -((( ( ~ ( ,)( ( rAp((( ( ~ ( , *(s *0A~D-4(oD( ( o (' ,o o o ~D* (10o ,o t  (-*o u0 ,o% o (,9o% -1*uD , o (+uC, o (*0P(r?Bpo# t  (,0ol +om o o o[ - ,o4 *%D 0~E:s E~ (< o} rCp( o ,Fo +% o t  ~E o Xi2rp( ,o4 &~E*3K~ v0Q~Eo ~Eo &s s o ~B- s B~Bo o &*MM0o 8 o o o -oo o o o +'oF t  (,(,o o[ -u,o4 o ( o[ :q , o4 *:4n 0VQ~Bo ,=~Bo# u+ - ,(- o -+o Q &**LO0(; ,*(& (-R(o o  (o o  +"o ,((- X i2, o o *0\(; ,* (ol +om o (  - o +o[ - ,o4 , o o **A 0(; ,*( -*s o o o o ol o o o o 3+o o ,(o ( ,s ~|o  o *0o oh +DoF t {=- s }={=ok o -{=ok o o[ -u , o4 o oh +EoF t {<- s }<{<ok o -{<ok o o[ -u,o4 * P\zR0Q{=-*{=o o +( o , ( -Qo4 **$?0, o 0*(, -* o  8 o o od (, o/ ok o &,r/Cp(ui-Ao od (-sx oZ  o[ :q  , o4 **# 0o- +\(. ob ( - ]o2 o- +(. ob ( - 4(3 - o4 (3 - o4 **0'Wip0-*{F-*s o o o o o (o o (o s {Fo oh  +% oF t o { (m o  o[ - u  , o4 {F(o( o  8 o o : o o 9x{Fo o 9a o o  o o o o o >!s  o o  8 o o oh +)oF to o ( -+ o[ -u,o4 , (+,s (o o o o o  o[ :K  , o4 o o o +o  o  o o[ - ,o4 o o  o[ :S  , o4 }F*A|e2p6Q  .$R y 0{F,(; ,*( {Fo oh +/oF t o ( -{ ( - "o[ -u,o4 * *.o o ui9o 9o(; -&rpr[Cpoj rpriCpoj (A o o oW o o o o +To$ 3Ks0 o/ (; - o/ o  o1 o2 o o3 (o o4 (o5 *R0-*ol ( -*uk -*ol o o o? o o6 (o7 o o8 (; -o8 o(* oT o9 (; -o9 o(* oU o: o; (o5 *0B( o {PoH +oI oJ oo[ - ,o4 * 7 0B( o {PoH +oI oJ oo[ - ,o4 * 7 0B( o {PoH +oI oJ oo[ - ,o4 * 7 0B( o {PoH +oI oJ oo[ - ,o4 * 7 0e{QoK 2U sL oR sL oS sL oT sL oU {QoV &*01{QoW +oX oo[ - ,o4 * & b{[( t}[*0v  .  . +Q(?+I - o< ,{k-o }k+!,o< -{k,o }k{i(c*0! p(b (c &/sk}jo {j(b}i(,1(A od oe DsK of Fsg (h (A oM t'EsO oi (4(>rCp(j ,ok {\ol (8 rDpo {\Iss of r/Dp{\(m & &(n  (o \sC (D Xsp (q Ysr (s Vst (u ^sv (w ]sx (y _sz ({ 1s| (} Zs~ ( ( gs o  ( hs o  ( is o ( js o ( ks o ls ( ( ms o ( ns o ( os o ( psG oH ( qsI oJ ( rs o vs (? ( ws o ts ( ss ( ( us o {do*0{\- s` }\{\o( o +o As o o[ - ,o4 {\o( o (2o (ono +o oVo o[ - ,o4 s }bsz }fsz }g( o +o ( o o o[ - ,o4 ( (oo (, - (),()o( o o * o\ 0* o- +&(. o] -+o] 3(3 - o4 --*,(2{b(6,(2{b(6(7-#(,so(;-"rSp( t   (; - (:sz  (9(ono 8Io   oVo 8(    oQ :  (  (; :(2 o 9o9 o o o As o ()o( o   oy  o`(; - o`(5, o  o^,{f oQ - {f oy  o\_-{g oQ - {g oy ( :co4 o[ : ,o4 (<*A%'L  % c3q$U\ 0(; ,*ru p( -( +frk p( -( +Pr_ p( -( +:r=Dp( -( +$rQ p( -( +( o &*0oa ob  rKDprpsc of o -*o] od oe o/ s of o o(9o2 o- 8(. oa ob    rKDp rp sc of o ,U od o -Go] od oe o/ s of o o (9oo (3 :Z o4 od o - od o oo oh  +A oF tKop o -$so oop o  o[ - u  , o4 *.dN0E-*(8,,( (; -(% - (O ( , &**9>10.s oa o &riDpo ,o4 *" 0(9(ono 8o of o o oh +toF tP o o (; -S,Pi1JoZo (o ,7+' od (m oVoy Xi2o[ -u  , o4 o[ :? ,o4 *? 03!{_,{U,{Us o] }h +E()o( o o -'As o ()o( o Y X ()o( o 2  o9Woo oh  8 oF t(2o o 9{ o9As o o { (m o o o o o o ,o , +o ()o( %Xo o oh  ++ oF to 3 -s o +  o[ - u  , o4  o[ : u  , o4 ()oo o ()oo o ()oo (o ()oo (o }c,()o +T()o( ,G()o( o 14()o( o o ,()()o( o o ()o ,F()o (B ,2 o +o   (Bo[ - ,o4 }h{T,{Ts o] }_*ALz8- 0"(A oM rDpoN o Q  .3 , _ (om s s {\o( o  +j o o o o ,4o ,%- o +1,.o -% o +,+o , , o  o[ -  , o4 {[,' o 0 o 1{[ so o  + o {\o  o[ -  , o4  o  +l o   -&-{f o oQ , o -  o , o o 0 (B{\  o  o  o[ -  , o4 *(aw #? Vy 0A#()o( o +o o ,,(Bo[ - ,o4 *%6 0*'-*o o 1*o ( (2o -*o -*s  o oh +&oF tX( +, o o[ -u,o4 {c,o ,;o +o o o o[ -,o4 {coo oh +4oF t o  o  { (m ( - + o[ -u,o4 9|o oh 8oF t  o +-o   o (   o  ( -  + o[ - ,o4  - ( +  ,  o  9o  o   o o   o o   o l o ls o  o ,0  o o   o o   o ,+o  o &o[ :u,o4 o +o o o o[ - ,o4 o o 0Bo 18o +o o o o[ - ,o4 *AS3& AA: k!# # 0|{\,s{\Iss o {\Hss o {\Ws o {\Ks o {\Ls o *0y+,o - rDpsz zo  @Vo  9 o rEp((N -:s rEp(o Pss o o oS  o  o o rGEp((N:s rGEp(o o oS oT 1o oS o  +o oS o &s o oS oT 1o oS o  +o oS o &9l{c,{co or}Ep( & -(; -s o &oS o 9o  +q o  s  o Oss o o o (; - ( - o  oS o &X o - u  , o4 s rEp(o Oss o 'o o o  o oS o & ,  o o rEp((N  :s o oS o &s rEp(o Qss o  o oS o &s rEp(o Rss o o oS o & , (Y -+o! *~00S,oS o +# oF u ,oX od , o[ - u,o4 ** /;0}/()o -o()( ,`( o ( (' ,o ,o o -++ -o ~ ~ ([&*}a*0y${\-*( {\(d ow (Y ,(Z . (Z @3{\( ov +(~{Z,{Zs o *01{\-*o @{\o! (Y -{\o +x(Z 3{\o +](Z 3{\o +B(Z 3{\o +'(Z @3{\o + {\o {W,{Ws o] & (Y -` +(Z . (Z @3` (n (J(G*o -{\o! (J(G*0O1 (*;\o o o o ()o :4rEp(s `s o o o r[Fp(s o o rFp(s (),()o +o cs o o o  &rFp(s (),()o +o ds o o o  &rFp(s (),()o +o es o o o  &rFp(s (), ()o , ()o + ()o o fs o o o (*3rps o o (! ,.rGp(s as o o o rCGp(s bs o o o *0{Y,{Ys o] \sC (" Xsp (# Vst ($ ^sv (% ]sx (& _sz (' 1s| (( Zs~ () ( gs o ( hs o@ ( is o6 ( js oA ( ks o% ls (# ( ms o* ( ns o+ ( os o, ( psG o- ( qsI o. ( rs o/ ( ws o& vs (: ts () ss (* ( us o0 {do*0Q2o  ,^o  raGp(o ,LraGp( Q {\o _,{\%o `o _,{\%o `o o  9o  roGp(o 9rGp( Q.+ ,VrDp( Q.+ , }^+}^{^,t( o (' ,` rGpo +P{^,H}^rDp( Q.+-%( o (' ,rGpo  (y*0 (),o -*{c-* {bo o -&s {co{bo o +{c ()oo-*o oo2 {bo o ,{bo o3 &{bo o }c*0( o /*o< -*( o (B ,*o o -*{m,,(4rSp( t  (; -(:}m(),&()o  -()o  {l.(~{a, (?}a{`1(5 1(5 {`Y /*(5 }` (z*0N3()-*s ~6 o7 o8 oo9 o: o; (|&* AJ0g4{e,(; -{e-*{eo> o? +(@ o , o (A -jo4 **+*U05(A oM rDpoN o Q (),|0 #+l ()o  , # ( ,()oB ()ov + ()#ov ()oB ()o  }l*0f7,{(B - {o)-*{o) o( o  8  o o 9{o3o oQ :o o 8o o 9o o ol 8kom ( , ݢ ud,R udoK o  + o  t+( , bo[ -,o4 u9 uo' ol +oom ( , u#,Ku#o ol +om   ( , o[ - ,o4 o[ -[,o4 u#,G u#  o ol +om   ( , go[ - ,o4 o[ : ,o4 o[ :E ,o4  o[ :  , o4 * *A0 y( <| % ~! y; 9U 09 (9(A od oe oM 1r( u -(N ( (,Mt {} (B ,%{~oO oP ( }~+oO oP }~ }} -}}}~*0t(,](' ,T{}(B ,F{~,>rGp( -(Q {~oP o .(A od oe oR }}}~*Z~( t*0:((B - (o< -* s sT oU oV oW (X (o)o( o  8 o 9 o 9 o ( (o2o &o9o oh  8 oF tX,{o o  ,g  o oh +4oF tH  u+, + o  o  (o[ -u,o4  o[ :g u,o4  o[ :  , o4 &oY o *AdA=`_$ IH10~;P,-*u),cu) o oj 0*o oh +oF tH , (o[ -u,o4 u,cu o# oj 0*o# oh  + oF tH ,  ( o[ -ݴ u  , o4 u,uo o 3Po  (; - o  +7oZ ,*o  ,!o  o  (; -o  o  o (*u,u(*3+^+0D<-;~ o (; - o +8o, oj 1*o, o o (; -o, o o o, oh 8oF tH 9u9u o o 3Ko  (; - o  +5oZ ,)o  , o  o  (; - o  o  (; , o (+ o (o[ :Gu,o4 &*A4i)@@10Q=~(; -~(; - ~(; ,-r;Hp(rwHp(rHp(PrHpo[ PrIp-rp+o\ o] ~(^ o_ ,'o Y~o Y~o Xo rp~(  ,DPrIp ~~raIp(` oa +:PrsIp ~~(` oa Pob *0=~(; - ~(; ,r;Hp(rwHp(PrHpo[ PrIp-rp+o\ o] ,?PrsIp ~~raIp(` oa +5PrIp ~~(` oa Pob *0>((B - (o)-*(o)o( -*~9b~- sc ~- s ~- sd o  8 o o 9o o  8 o oe 9 o o ol  +! om o rIp( - +  o[ -  , o4 ,Po o ol  +% om o rIp( ( o[ - , o4 of ~og  o[ :.  , o4  o[ : , o4 ~,B~oh  + (i of  (j - mo4 ~ok ~,K~ol +(m o o- (n -no4 ~oo ~,H~op +(q (r (a&(s -oo4 ~ot *A. 2K w y '#N$r0a?oo +o (o[ - ,o4 oo + o ( o[ - , o4 * & <V 0@-*~- s ,p(o)o( 9~o o +3 o o ~(-ow ,ox ~o o[ -> , o4 ~o +o ox o[ - ,o4 *??~  0+A(; ,*( o (B ,*((' 9(o),~(o) rp (o*  E ++ ++o , o o ( -rp+oy ,Yo '.Mo *.Ao .6rJpo /$r Jp(z ;(z ;( ({ &*'0Do o  EC-*o o o *o o o *o o o *o o o *0sPo (^ io o ( io o o o -+o o o o o o ,+o *0R u,u( 8uk,uk( +qu#,u#( +Zu,u( +Cui,ui( +,u!,u!( +uC, uC( ,rGJp( ok o *05(; ,*(, , o\ 0* o- +a(. ob ( - +Oo2 o- +(. ob ( - + (3 - o4 - (3 - o4 *R(z(n01Ts o o oo o o( - r/Cpo + o o  ,o o 9od (; :(; :od ( 9 ^( ,/( o ( ~ ( ,/( tE + (,oa ob s , oo o &( ,( ~ ( , ( o *0Xs rWJpo o o o (o o ol +)om ui ,( , o, o o[ - ,o4 *<6r 0MZ, oj 0*s oh +oF t  o o[ -u , o4 *:0urJp ( ~( rps sn ( rJp ( ~( rps sn ( *0g]o ( rJpo o o G rJpo o o t  - (0o *o *0^$o 1o rJp(o -hrJp(o -[rJp(o -NrKp(o -Ar Kp(o -4rKp(o -'rKp(o -rKp(o - r%Kp(o ,**0s`(A oM (oN o -~ *( ( r-Kp(- ( e+( hQ( (; - (~ *0buQ,Q ( Q*uk,k ( k*u, ( *u',' ( '*ul,l( l*um,m( m*un,n( n*uo,*s z0du -*o &o ( ,*o @( ~ ( ,*(~ - (d&1o o ( (d& o  ,o4 *N6 0weu-* @( ~ ( ,*(~ - (d&1o o ( (d& o  ,o4 *46j 0g("s s o ###0@#0@(  o o #X@#X@( s o *0h(- o. ,o/ o0 o1 (2 8o3 , (2 +ho4 , (2 +Io5 , (2 +*o= ,"o> (? (@ (A (2 *0Sjo (2o +$( o o-( , o ( -qo4 *1D0'lu (  &# *0un(A od oe oM (A od oe o 1:s rILp( o ( ~ ( ( o o &/*~ *0po ( o (' -+o5  (' ,To7 o o: to - o + ,o4 o< ,o4 *Mc =;x 0fqMs (: (A od oe o 1:s rLp( o ( ~ ( ( o o &*0Xrto o t~ o , G ,o ( , (  +G ,o4 * ?L 0lsto o t~ o ( , (  ,#o ( , (  +GG ,o4 * R_ 0mtto o t~ o ( ,(  - G.o o ,+G ,o4 * S` 0nrto o t~ o - G Bo ( ,(  - G o o G ,o4 * Ub 0v~ 3~ *uV ( ,u , o uV ( ,s zo ,rLpo o ( +Go 3.rMpo/ oo0 oo1 o( + rkMp(> (A od oe oR (~ *0krMpX( Ъ( gs s (4 rMpX( Ъ( hs s (4 *0x9to o u (' ,Yo -o -o ,As rMprpo ( ~  ( ( o o &(  ,o4 **p 0zs :sz ( o o5 & 8q  (  o  *85*oF ( to oy  %X s[o o -rNp(oK+o oKo=o o   (%o?o>o oMs   o  rGNps o  o  oEs   o  rNps o  o  oG  o P3 (  & ,o *o[ :*u++,+o4 :8@  ( &( o o5 &{otFo( o -ko(  o ,So ( to ( o o& ,o 8:o  ,8,oF ( t%Xs[o oKo=oMo  oJ(o 9F;>   &s ( o  !"#$ o l o l[%ll[&%&6'##l o lZ o l[i$$Y["+$$l%Zi##Y[! !"#$o (%o?oo (%o?s ''o 'rGNps o 'o 'oEs ''o 'rNps o 'o 'oG+o (((%o?o>o ))o P3 ( & ,o ,o[ :,u--,-o4 :*AVNVfVk =H"-O"2T Uns w0{{}{(! (tF {o( o 9{,=( ( rOpo ( rKOpo ( rOpo rOpo *( ( rOpo ( rKOpo ( rOpo rOpo *0~|( &,4E +rPp+r1Pp+rMPp*E +raPp+ryPp+rPp*0H}( ,R(" ( o 9+( ( rOpo ( rKOpo ( rOpo raPpo *-{-{,R(" ( o 9( ( rOpo ( rKOpo ( rOpo rPpo *(( o (' ,rPprp(&(tF o( o ,<( ( rOpo ( rKOpo ( rOpo rPpo *0~({}9~(# ($ {(! rPp( Q {~%zs0sssss s4o{}o {}rQp(o2 {}o3 (*0^o{},){}o t7 ,rPpo'(4 &((# (% }}*330(o  9o  r|#p(  -u{},m{}o tF,[{}o tF r|#p( Q.+ o.*oo-{,{o (&*0-*o'  Ev~*( o (tF {o( - {:}o}(  }}o r5Qp(  rp(&( o 9( ( rOpo ( rKOpo ( rOpo rSQpo *{}{(" ( o 9{,=( ( rOpo ( rKOpo ( rOpo ryPpo *( ( rOpo ( rKOpo ( rOpo roQpo *(( o (tFo&( o o5 o7 o8 o(   o   o& t  o ,prQp(   rp(&( o ,D( ( rOpo ( rKOpo ( rOpo rQpo (' && ,o4 * 02-*o'Ev*( o (tF {o( - {:}o}(  }}o rQp(  rp(&( o 9( ( rOpo ( rKOpo ( rOpo rQpo *{}{(" ( o 9{,=( ( rOpo ( rKOpo ( rOpo rPpo *( ( rOpo ( rKOpo ( rOpo rRpo *(( o (tForQp( rp(&( o ,D( ( rOpo ( rKOpo ( rOpo rRpo (' &*0( ({,"(< (' ,{(< o= o( ~ r5Rpo) raRpo , o ( -raRp'o *-k( rRpo* -Is+ rRpo, rRpo- rRpo. {o/ o0 ( o1 ( rRpo *( rRpo2 &*0 YECg8t}*t}*tz}{ss ot *tz}{ss ot *tz}{ss ot *}*0-s2 o& o< o= rpi( ( (4 s2 o& o< o= ~( o> &s2 o& o< o= rp ( ( (4 s2 o& o< o= ~( o> &*0Z (( ,*( ,8o +o ( , o[ - ,o4 * *&$J 0( ,* ~,~o? &-^ o ,o ,o s ( +( u - Q~- s@ ~oA &-*((; -(o , (o# ** *%[0>-* oB oC ( &u - s oD (*0,-*o o o0 (; -o0 +oE o (; -o +oF oG (; -oG +oH oI (; -oI +oJ oK oL o. (; -o. s oM o/ oN oO (; ,oP (oN *0a}}( ( oR rSpoS rSprSprSpoT oU (rSprSprSpoT oU (rSprTprSpoT oU (rSpr&TprSpoT oU (rSpr@TprSpoT oU (rZTprrTpoT o (V Z(&( oW ( oX rvTpoS rTpoS ( rTprTpoT o (V oW &*I] 0 (f &&*10u>,.u> o , o u -*o u (*u,u oJ (h *u9to u ,Ru, toI ,; oi oj+*u,uogo (+(to u,Eoj ,<(o)oj o *u+,o rDp(o ,(*0 u ,oE u+ +u+ 9ok ( - ok o +~ }ol }(-]o u,Po t~o5 ui (m , o }o t~o5 u }(-5,2on ( - on o +~ }oo }(:u#,zu# o -+ o ui-! o o 1 o o ui,{o ,ro so}o}*u>,Aon ( - on o +~ }t>o u (}*0l(; ,*   +<o (q -o -.o _3. 3 X +3 X o 2.3*Yo *0Z-~h о( о( si oj s2 o& o< o= rVp( о( (4 s2 o& o< o= r"Vp ( о( (4 s2 o& o< o= r0Vp ( о( st (u s2 rFVps o& &o& o< o= rpi( о( (4 s2 o& o< o= rVp( о( (4 s2 Go& o< o= rVpG( о( (4 s2 Go& o< o= rVpG( о( (4 s2 #@s o& o< o= rVp( о( (4 * 0M{-*(-"((; -(- {ow *{- sx }{(oy {((; -(rAp((  +(oz {o{ &(-{o - {ow *{o ((| o} o~ 2Z(,R(u ,E{o ,(-0#@#?#@#@s (*#@s (*0|~h ( ( si oj r*Wp ( ( /sn (4 r6Wp( ( /sn (4 *0<sT oW  s o s> (X ( &o *!20{-*{u,v{to# Zo> ( ( o> (? ( o> (@ ( o> (A ( s*{3{s'**0{-*{,{* {u ,{t  8{u,`{3{(( +i{3{(( +F{(( +,{u,{to% + {o }{*0rLWp( ( &** 0rZWp( ( &** 0-~h ( ( si oj s2 rpo& o< o= r*Wp ( ( (4 s2 Go& o< o= rpWpG( ( (4 s2 o& o o< o= rWp( ( (4 s2 o< o= rWp;( ( (4 s2 #`@#`@s o& o< o= rWpЙ( ( (4 s2 o& o< o= rWp( ( (4 s2 rpo& o< o= rWp ( ( (4 s2 Go& o< o= rXpG( ( (4 s2 Go& o< o= r&XpG( ( (4 s2 Go& o< o= r>XpG( ( (4 s2 Go& o< o= rZXpG( ( (4 *0[( o o o  ( ,*( o o5 o7 o o: o ,yu(' 9o   ( :o   ( 9 o o: u(B , +o |,o4 u(' ,]o   ( -Ko   ( ,9 o o: u(B , +o ,o4 ,o4 o< , o4 *Ad - H; >O 0-# rYp( ( &# *  `SUVWATAUAVAWH(HH-DHMHHN(HHMH艽HFH9L=4vALII3Ʌ%AHL%%L5L-oIM^HMM3H?HHuAHL%%IM&HMM3H?HHuL5uAHL%`%L=1L-IMHMM3Hf?HH_uAHL%$IMHMM3H.?HH/uL%%H=H keHLM3HHuL5uAHL%$L=vL-jIMHMM3H?HHtAHL%w$IMHMM3Hs?HHtW$tHL-#L%H HMM3H)?HHZtHFHtQ+t8HGtH3҅€95t#L#IH(A_A^A]A\_^][HH(A_A^A]A\_^][`H#HPHq#H@Ha#H0H(H sHH3pH(SH &#HH,H9HsHH fIHHtr8HH$sH [SUVWATAUH8r8HH@9E3H=5zHzHHH3rȅt+zHH9#8HrLH ^HH^HHu!HHGr8L`@\rHH~H^H tEHH\$ MLHHT%A<$HIH8A]A\_^][̰SUWHHl$ He3HEPHEXHE`3HE8HE@HEHHE HE(HEHEH ҏHHRH]hqHu H;8HHM 1HM HHEPHAHEXHAHE`HHMP H?HO9tHW;H?HW :HMHMHHE8HAHE@HAHEH1HHM8H?HO9tHW;HH=HHM8ȅufHɎHM8xH]hffffH=HHMPMȅfHHMP6HEhHep_][SUVWATAUAVAWH(oHH XHHO HHu >HV(HW H_HDEtz#HH-#HHH;H[3$HH1$HW>HoHoH sHH^$HHoHoHHHH HhHHLHO(ȅuH(AoLIIHH dHL3HLI3}HHnLIL=nL-ɌIMHHHAH-nUL%nHHA$HnL5n8HHAL&IIMJHHHAUHHA$Hm8HHAH(A_A^A]A\_^][SUVWHhHl$0HM`HeHEHE3HE9U/mLIIHH] ,H;HLHH HtHH9tHH HDH \HHmH]?Hm;HHmH HHQmH!HH}(3HlȅtHHLHHQmHM(HtHƪ9LHu>H-mHu6KHHqH9mlHH nHHl>H3HEMHEHMHHHlHXHlH(H HHlH3Hl HHlHH aHD$ AAHHHHLHHHlHHLHM`9HUH] Ha;HLȅHU H `nHtHB8HLHe8_^][SUVWATAUHHl$0򉵘HHHeHEHE3HE?H]H HE HHHt9QkHH ׈LI'Le(E3Dm0H;HLHH]8fDHq;HLHH]@H]HADm0D;NH SHHrjHuHHL>HH`jHHLHHHjHHLHjjHH HH(jH3HHHjHHLLE3HiȅXHE8HMVȅ$HHL3HMHHEHMHH}iHXHuiHHLHH t^HD$ AAHHHHLHH2iHHLHuL]@IIHh>HHHhHuMHH H9hHH UHHHA<$HIH?HHx HMAYHMHHtH9LHLe(Dm0H]8H;HLȅ#HM8HtH9LLe(A<$IutyhHu HH L-]H=rH \HLM3HH \+HHHH^HHH 9IHeXA]A\_^][SUVWATAUHHHi0Hl$0Hm0H*HHA]A\_^][SUVWATAUHHHi0Hl$0Hm0HMHHtH9LHHA]A\_^][SUVWATAUHHHi0Hl$0Hm0HM8HtHY9LHHA]A\_^][SUVWHHHl$ He9/HH]kH;HLHH HtHH9tHH HH kHH9HI9HHu@H>HLHH HtHH9tHH \H؀;H?HpȅtiHXHeHPHeH@HeH(HeH HeHHefH>HLȅ#HMHtHޢ9LH]fH;HLȅxHMHtH9LHe(_^][ SUVWATAUHHl$0HeHE@3HU(HU0HU83HE HEHEHH "HH HEHHHtHumH HH{dH]P?HHM0HMHHE(HAHE0HAHE8HHM( HH]XH]`H zEHHcHu@HHL>HHcHHL3HM HHE HM HHhcHXH`cHHLHH _XHD$ AAHHHHLHHcHHLH}@H]XHHL?HHcHHLHHbHHLHHbHMP9HHM`HtHN9LfDH!HHM(ȅRfHHM(vHuP>HtKHEHH8L-L%lH ZHMM3H?LLú H0bHexA]A\_^][0SH `LIIuYH 5Ht:ƃ3$~`8H`H3҅€9`H [̰SH _LIIuQH `Hƃ_8H`H3҅€9`H [@SUWHPHl$ HeH 4HHHt9_8HH(9HI9 HH]6fDH);HLHH }HtHH9tHH HH]'`H8HLHH}H?HLHH} HHL;HHfȅtHHHLHMEHM HtHu9LH]H}DHI?HLȅSHMHtH69LH]fH;HLȅHMHtH9LHe0_][SUWH0Hi Hl$ Hm HM HtH9LH0_][SUWH0Hi Hl$ Hm HMHtH9LH0_][SUWH0Hi Hl$ Hm HMHtH[9LH0_][SWH(H=HNHHKHtB9HI2a HC8HXH)HL HH(_[HH(_[`SVWH 3jHHH׉H?HAHHtyHHRHt HH;t3Ht[e\HH {LH lRHt HH;t3E3HIHH z>HZ]fHIHH讼HHtwHH RHt HH;t3HtY[HH z{LH QHt HH;t3E3HI\HH Jz>H\HHHHHtwHH{QHt HH;t3HtYA[HH yLH HQHt HH;t3E3HI˻HH y?HF\H _^[ÐSVWH0HHHHH5Z8@dD$(HT$(H My0?LHHOLI8@hD$$HT$$H yLHHLI8@`D$ HT$ H xLHHH0_^[SWH(H=HH3H HK3HƀH(_[p`SUVWATH H=L%dH-DOHMHML3H H5ZHH=HMdHML3HHH A\_^][SUVWH(H lwHHpHEHu]H HH NHAHHjHYHH OwHtHH9t H HHHpH(_^][PSUVWH(H HHxHEHu]HuHH ;NfHAHHʸHYYHH vHtHH9t H BHHHxH(_^][SUWH0Hl$ HHH]0HeEHUHHH?LH EMMtHI9tIH LfHYHHUHHe_][@SUWH0Hl$ HHH}0HeEHUHHHt HHPxHH LHtHH9tHH HHLHIHUHEHe_][̰SUWH0Hl$ HHH]0HeEHUHHHLH LMtHI9tIH LfH9HHUHHe_][0SUWH0Hl$ HHH}0HeEHUH^HHt HHPxHH ~KHtHH9tHH HHLHHUHHe_][̠SUWH0Hl$ HHH]0HeEHUHHHߵLH JMtHI9tIH ULfHHHUH}He_][ SUWH0Hl$ HHH}0HeEHUH.HHt HHPxHH NJHtHH9tHH HHLHHUHHe_][̐SUWH0Hl$ HHH]0HeEHUHHH说LH IMtHI9tIH %LfHHQHUHMHe_][SUWH0Hl$ HHH}0HeEHUHHHt HHPxHH rHtHH9tHH HHtLHHUHHe_][̀SUWH0Hl$ HHH]0HeEHUH^HHLH mqMtHI9tIH LfHH!HUHHe_][SUWH0Hl$ HHH}0HeEHUHHHt HHPxHH CHtH9 t HdHؐHYLHHUHHe_][̀SUWH0Hl$ HHH]0HeEHUH>HH_H BHt H9tHHLH HUHHe_][SUWH0Hl$ HHH}0HeEHUHHHt HHPxHH FHtHH9tHH >HHLHiHUHeHe_][pSUWH0Hl$ HHH]0HeEHUHHH/LH 5FMtHI9tIH LfH)HHUHHe_][SUWH0Hl$ HHH}0HeEHUH~HHt HHPxHH EHtHH9tHH HHLH9HUH5He_][`SUWH0Hl$ HHH]0HeEHUHHHLH EMtHI9tIH uLfH HHUHHe_][SWH8)t$ H\O8H PHH|HH9L8HPHH D f8HHDž 5V*H8HOt5Uf.zt3t2H8HOH8HzO4H8 UH\OHt8HD؋D;tHtHƃC|~ 謝~裝D؋C|D+A|#茝C|D$ LLź HVH8_^][pHQHpSH HHHtH83Hm?H [@SH HHHtHs8H-?H [SWH(IHHȅu ƃ%H?HWHbHH(_[HH(_[̰SVWH IHHH?HGHHHHHW9ȅt H?H DHHX*HHHHW9L˛H8>HHjHVHtaHO9=HHW9聛ȅtHHW9wHHW9LYHHBfH _^[̐H̀SUVWATAUAVAWHHl$ HHHeHEHHE@HE83HMhHMpHMx3HMPHMXHM`HM HM(HMHMHHu*H ;X趾HH2;HLHH998H轙LLJH2xA<$ILHL-kH ./HMHH?HH_йHH $;HKH莹HHHuOHaH7HH Q*HtHH9tHH 艹HH>ȅu HHH E*HLIݓL HHs8HLHs8HLHHHs;HLH>HV:HMpHMHHEPHAHEXHAHE`HHMPLLA}II艔ȅLE@HUHI6HEHHt@ 3ɅH8LE8HUHH5ȅjHE88HM8HU@LMJA>IIJ63IG6ID6L=H ^(豷HMHHxHI6H8H28IH"A}II:>HF(Ht@ 3Ʌfu$>HV(HHtA>HI5>F4t-H9IȅuH9I躑f>F0u5H9IےȅuH9I肑ffH'HHMPmȅfH'HMPVHLHfHqp;HLȅ[HHtHSp9LE3HDHA_A^A]A\_^][PSWH8HHD$ H趐ȅt3 H^HAHˑu14HD$ H]HAH袑u4HD$ fDH]HAHsu3HD$ H]HAHJu3HD$ aH]HAH#u 3HD$ :H=wHwH豴H`9LD$ HҐfHD$ H8_[SUVWATAUAVAWHHl$0LMLLHHE8He3HE HE(HE0HE@HEHEA?IwIH C%>HH\L3H/L\MHH 9NLLmHH\$(D$ E3LHI2LmPA}IE8H@`HoEg(IEIPpHI}8I_H 1藳LH\$ LLAILmXH]HHS:HR`A}INHHM8*IW :HMHMHHE HAHE(HAHE0:HHM ƍLA}IuI}H $HH[[L3HLO[MHײH L軲LH\$(D$ E3LHID1A?IG8H@`HIIPpA>HIDȅu}Ee(IIPpHI8I]H v0ALH\$ LLAIIW:HR`A}IIHM8IUMIՍfffffHJHHM 蝌ȅfHJHM 膌HH]PHHPp?HHlȅuHHPpLEXHHU;H08HvHHHHu`LHk>HLHH cKHtHH9tHH #HL-/?HAUA<$HI迌ȅuHH 5԰HHHW`;HK葰HAULHI脌ffffHj>HLȅ<HU`H !莰HtHj8HLHexA_A^A]A\_^][̠SUWHPHl$ He3HE E3LE3HE3HEHu3LE Jȅ.HH覊ȅuHߋȅu3h3HEH] H蒊HEHM荊H]HEHUHH?H#HMH H?H#3H;t2fHe0_][SUVWHHHl$ IHHeEH ^IHH-H]?HW;H-H gWH;LH-EHMHtHi9LEHe(_^][0SUVWATAUAVH@Hl$ LLehHeHEEH7Hh8HLHh8HLHH]Hh;HLLA<$IL$9HI`9,8H HHLLmDHYhA}ILHH HHtHH9tHH 躭H؀;H{,HHCHHt@ 3ɅuwHtrHG~jA>IN ;HSH薈ȅtO3;HcH;sdH\I$IPpHH,A>IN9H͇fHG;|HqgA}ILȅBHUH uHEHtH@g8HLH]LehDHg;HLȅLHMHtHf9LHe A^A]A\_^][SWH8HHHD$ HHtNHtG 3Ʌu1HHt%9LD$ HȅtHT$ HH8_[̀SUVWATAUAVAWHxHl$ LLHHHeHEHEHEt0HHt$H E`HHLHHNVƇ3fH8HA8HBLA}AuQL5H ۪HMHH袆HI)H&8HA8HHL=%8HA8H߅;OE3Lm IHu(A<$IL$HE39HI09lHHHH]0d@Hd;HLLH tDMtHI9$tIH LHA<$IT$08LEHȅIT$8HE8HMLML=H 5舩HMHHOA}HI'IL$0IT$8^(HI'AT$YHM(IAT$XI'AtAtLm 3IHl8H$HAFE89MA(A<$IL$@9HHHH]@~Hc;HLLH CMtHI9tIH 誨LA;AC8u:HuH BqHHe'Hu(>IH)fH c;HLȅeHU@H >HEHtHb8HLHHu(Du8H]0fffffHb;HLȅHU0H [ΧHtHzb8HLHLm Hu(LHHA<$ID$8P@9[&HHID$8PA9C&HHIL$9I8;H"&HZHIL$9I<;H&HI誦MtH8IH%HL%!8HA$HH8HA$8H~fH8HA$83Hw8t9HHH8HA$83H?;HH0%HXH)%8HHH88HHHH|>HHH]H(HQ`;HLHHsfffH!`;HLȅuHMHHtH `9LHfDƇHHt$H )HH΀LHHNVƇHeXA_A^A]A\_^][̰SUVWATAUAVH`Hl$ A؋LLHe 8H HH-MHH_9L8H HH U谤f@2@}tuÅtƃ3@@}L*_8HMALH>H HHOHuH LI8LmI$98HLLe @H^A<$ILH؀;HS@H^A>ILDtRt=AÅuA}HI}[@DžtSuH>HH}8AÅt0.t#AÅt>HH}fffffH]A<$ILȅ!HM HtH^9LfDLI$HtdLmA}I}Hu>H}~@fHuI$H 'pHLIH7LIHOWHu>H}HH](0HI];HLI$9HJ!ffH];HLȅuHM(HtH]9L3HM9}HH}0DuLH\?HLHE3@ƅu;AƅuI$;HS@9p}ȅt;u@D;tH9| HII$;D9EHE fffffH\?HLȅ,HM0HtH[9LHe@A^A]A\_^][ÀSUVWH8Hl$ HHeH8Hu8H{HH}AH[?HLHЀ:t@ƅtHfffffHi[?HLȅuHMHtHU[9LHe_^][H('Ht" t  H H(̐SWHXH3HD$@HD$HHHHL$0LHL$0HHD$@HAHD$HH|$@H8HHLHL$@HHD$ HAHD$(HT$ HLAHWtHRHHVHX_[ХH(H;HL)9HtIH9tHI豞HHu 3?DHY9Lȅu2 HH 8IHu2H(PSH Hu~H 8 HHP8HHHEHHPY9L8HHH fuH 8H7H [SUVWATAUHHl$ HHHHHeHE@HE8HE0HEHHEPHEXH;H9qxHK@LE8HU@WH8LE0HU@HxȅHE08HM0HU8HHH J7赜HHxH}`;HKX9xHHHH]hZHW;HLLH 6MtHI9tIH fLHU0HHt?HHvHW;HLȅuHUhH %HtHX8HLHHHtLA<$A$~LHM`9vHH]p0HW;HLA<$I$9HvfDHYW;HLȅuHMmHEx9HI9HI092wHHLLHVA}ILHH 95HtHH9tHH HA<$I|$@>HN0HV8HvHHHHE3LHPpu Hux#HUA}ILȅZHH kHtH'V8HLHMxHM9HI@9(vHHHHH}`IHU;HLHH 54HtHH9tHH ՙHfHHDž?HtLLgH0UA<$ILL>HN0HA}I]@uHHHHE3LHPpuL'HTA<$ILȅzHHtHT9LHHu6HLHU0H芽HHt"H}`?HH@sH}`HH}`HH9H9Hs>F83҃€;HVPHF<*ȋF@*3HE HE(HM L] IHEICHEHUHt4VDHVHHFLt3Ҁ;H?HH tHHH1S;HLȅHH (蛗HtH7S8HLHM`9rHHH5DHR;HL?H9HqfHR;HLȅuHHtHR9LH?H9 rH]`;HqxHqHH.H_R;HL?H9HpH)R;HLȅuHHtHR9LHA]A\_^][SUVWATAUH8Hi Hl$ Hm HUhH HEHHtHQ8HLH8A]A\_^][SUVWATAUH8Hi Hl$ Hm HMpHtHQ9LH8A]A\_^][SUVWATAUH8Hi Hl$ Hm HH xHEPHtH0Q8HLH8A]A\_^][SUVWATAUH8Hi Hl$ Hm HHtHP9LH8A]A\_^][SUVWATAUH8Hi Hl$ Hm HH lߔHEXHtHwP8HLH8A]A\_^][SUVWATAUH8Hi Hl$ Hm HHtH)P9LH8A]A\_^][SUVWATAUH8Hi Hl$ Hm HHtHP9LH8A]A\_^][0SUVWATAUHHIIHHD$0HD$(HD$ HH V.詓HuHH .蕓Hu3H=).HHvHtHHf8HBLHH -F8H*L}IHLMt8H@\HHE\HHZ\LLHI!HLD$(HT$0I5HL$0mȅHHL$(mȅ3HS8LD$ HT$0Hnȅu3 HD$ 8HL$ HT$(YHHu 3fHD$ 8HL$ n[HHD$ 8HL$ i[HHD$ 8HL$ t[LLHH;HHu 3@H ,HHHHIHH=i,HH趑Ht)HH覑8HHH5H3HHA]A\_^][̰SH H 8H^8HZHt@ 3ɅtHME3HH [HfH [PSUWH0Hl$ HHH}0HeEHUHHHt HHPxHH >HtHH9tHH 讐HHTLHِHUHՐHe_][HAH̰SWH(HH #HHkHHt LHHHPH(_[pSUVWATH HHHH-ĺL%U)I $蜏HLHHck?HHHH-vI $eHLHH,k?HHHH-/H )+HLHHj?HHSHH-5L%)I $HLHHj?HHHH-I $趎HLHH}j?HHH A\_^][0SUVWATH HHH-mH (YHLHH j?HHHH-#H (HLHHi?HHgHH-)L%(I $HLHHi?HH1HH-I $認HLHHqi?HHH A\_^][0SWH8 HH5H9 HÅu3D$ HT$ H x?HH H8_[ДSVWH IHHH} ;HCHtH*LHHH _^[HH _^[̐SH H3H5 H8H u*H8HuHvHH [HH [@uA8IPHH HٹMLºHSUVWATAUAVAWHHl$ IHLLHeHEHEH>LfMF(L~L} MHC4HE(HHH PHH}0H}8HhHHLII褶LLm@MH %8LI Lm@HE(HHHhHA}HI L%fH $ҊHMIHfHIe HN9` 8M3HW A}IIN >H^H@3HEHHHHhHLHI踵LLePMH %LLI LePHEHHHHhHA<$HI HNH 9HH`~HN98MĺH{ HN98IHq H q$謉HH` >HNH=2 9HH`~HN98LúH HN98HH M3H]XIHtA?IW@9½HH]XH1HHU 3ɉM`3EdEeH}u>Hcȅu/H ЈHHeH]HE8HMHUX eA<$I? 8Hc H}jHE8HMdHHuh>HdLH #RHH?IHHHEpH !HLEpIHcHHIHHH]XHbȅu!AHIcuHEeA<$II8HHR}`}`f>HcȅHUhH 與HtHlC8HLHL} Lm@LLePH]8H]0EeEdH]0fH ! HHH/HHhH?HHgH0HExH ] 訆HLExIHnbHH:EHUH ˆHHgIH#H@UdD3EH0A<$I8HHMtA}UdI=>H~L=.IHH 5ȅLIhHHLHI$LMH 輅HHpHNHEH9LJL8HHAHHH" HH[LIIHIhHLLA<$HIAH=L=IHLIH`HHHIHN9H8IHHHH 賄HHHH=-HIhH?HHHL-IQHMIH`HHHHN9H8HHHMt*Iqu3@A<$IfHA_A^A]A\_^][SUVWHHHl$ IHeHE:HPH?8HLHH}]H??HLHH 1dHHt4;HXLIHIPHȅtH],ffffHY??HLȅuHM=+HUH %HtH)?8HL3HEHe(_^][SUVWH8Hi Hl$ Hm HUH bՂHEHtH>8HLH8_^][̐SUVWH(HH QHH;HIHH *HHH8Hp@H-HUHt HUHH +u30HHH HtHH9tHH ՁHf?HHrHt8HHH(_^][̠SVWH0HH RH8HMHH .H3HHt8HP@9HH[ȅuVH)H8H HL3HLH3[HD$(D$ E3AH蠴H0_^[ЈH9MLºHHMLºH̰SUVWATAUH8ILH>FHNH)HHf[ȅHHHH 0f(HL-93AUDAt"H;H;HAUŃt$H;H;HFHNH?(HZȅH-(H\HH ut3H'H!HH :t3t Ƈ  Ƈ f 38HH3HȅHw'H;HD$ AE3H Ƈ H&H^HH w~t3uO8HH3Hȅt(H&H;HD$ AE3HHyLMĺ HH8A]A\_^][HH8A]A\_^][H9MLºHSVWH IHHLIIu.HHLȅtH3HLƃ HLLƺHH _^[HH _^[pSVWH IHHBLIIu& tHHLƃ H9LLƺHH _^[HH _^[H(3TH(H8H5%HHD$(D$ E3AH8H8H$HHD$(D$ E3AϯH8̐HHÐSH H8HȅtHH#H9H#H3H [@SWH(HHHtKH蓦?HHůH8HHHt"\HHUȅu HIH(_[SUVWH(HH-8H!HH0H8HH3Hnȅt?H-p?HUHt*HU8HXȅu @3Ʌ33u:HHLHغyL MȺHƃH(_^][SVWHPH3HD$@HD$HHHHHL$0 HL$0HHD$@HAHD$HHHD$@9Ht)HH=tH=@t H9HHD$@H9]HHtAH  yHHL$@HHD$ HAHD$(HT$ H^LHHNVHP_^[SWH(HHHt?Ht2H=H= t H=uHPHH(_[HH(_[ÐH!HÐSWH(Hڀ;HS~>3fDHVT8tG׋HATHVS;|H(_[0SVWH HHHA8A@93HuH9xHH= uH93KH=uH9%cH=uH9=H=@uH9H9DHHt$H vHHeRLHHNVHu.,H5H=t&H=@u.HMHcL,HIH _^[H2fu,93H/LHIH _^[HH _^[PSUVWATAUAVAWH(IHHZ}HM9jHLHHF?HHqH?J8HH<H5}H jHLHHpFH/H(A]A\_^][tSH HA8A@t t:ƃ 1ƃ HHLȅtH蒕Htƃ H [̠sH8HHHD$(D$ E3AߝH8psH8HHHD$(D$ E3A蟝H8@sHQH0sSH HHHtH賔8HbfH [sSH HH耔HtHs8H"fH [rSH HH@HtH383HH [̠rSWH(HHHH8Hu7H֓HH˓8H3҅€;HY7H蟓HH蔓8H3҅€;H*fH(_[rHMLºHqHMLºHqSH HIIP`HHHBȅtH莕HE3HH [HH [̐qSUVWATH IILHH #FgHHCHO HgHOIfHOHfHOHfHO(HT$pfHO0HfH A\_^][qSUVWATAUAVAWHHl$0ML0HHe3HHH3HEhHEpHEx3HEPHEXHE`HE8HE@HE HE(HEHEHLA<$IHI|$HHu"H Ht+fHH@HHeIL$90AH=oHeHHH@HeLIl@LHeLIR@LHFHtLt$(L|$ LMIH迓HFHtLt$(L|$ LMIHkHFHtfH~0HHH i$eHLHH@?Lú HLt$(L|$ LMIHHF(HtMMIHfH~0L% LHHHdHMHH_@HH?LMLú HH~0HOdHLHH@?MLú HLAH~0HH dHHLHH??MLú HAA<$IHM8>HM8HHHAHHAH)HHb>LA}HIMAfHq7HHJ>ȅuHO7H3>H:HM =HM HHEhHAHEpHAHExH0$HHMh=La;HHMAfH=6HHMh=ȅuH6HMh=@H:HMm=HMHHEPHAHEXHAHE`H0)HHMPE=L;HHMAH=Q6HHMP-=ȅuH56HMP=fHA_A^A]A\_^][plSUVWATAUAVAWHhHl$@MILHHeH< HH %aaHhHHHEHbHHEHN9HI9H;HLHЀ:ttHR@?H5Hy;HLȅuHMHtHe9LH]PH}DH5yXzH,YzHXH93HK9J4LLeYHA<$ILH>tHV@?HU5ȅtHK >HV@9L4HA<$ILȅuHMHtHh9LHe A\_^][bSUVWATHpHl$ He3HE HE(HE0HEHE:HM2HMHHE HAHE(HAHE0+HHM 2HHu8>HHHH WHtK8HH WHHt-;HAHH%H4HH>H HHH @WHt8HHH9HH .WHHNHH VHu6螁HHDH9HH VHH]>HHHVHtOHHVH؀;H9*HHH9HHf>HH W2VHH]@H;HHH09N1HHuH]H>HLH?t:Hȅt*HH UHu;HHwDH>HLȅuHMHHtH9LHu8H]@;H>HH">HH a,ULMt\H }(UHHH ITTHX8A<$ILHHHHT@H(HHM /ȅfH(HM v/HePA\_^][0_SH lH SjT%HHH97HH uHtHH9tHH MTH؀;HKHH [^SUHHHl$ HelH 5SS諂HHYH9HH HtHH9tHH SHH]H蔂Htv;H.HH]+H;HL8HP(HH ISfH;HLȅuHMHtHu9LH]HHe(][]SH lH ?RR赁HHkH9HH HtHH9tHH RHH袁HH [̀]SWH(HlH QRL?HMAX|lffffHHLHLHtIH9tHIMRH襀ȅuHoHL}fDHHH(_[HH(_[\SVWH HٺlH QQ;HHtFLHtIH9tHIQH@ȅu33HJfHH YQHHuJHH BQHu%HH .QHtY8HpH8Hp7H5?HHDEtHȅu2H _^[[SVWH HlH OPL ?HMAXH HLH5HHUPHtJt5H HL;t"SH HLHHPHtH HLC}H _^[[SH HٺlH OOH*ȅtl@HAHH*ȅt2LIIHHH*ȅt3Hdȅu H\H [`ZSUWH@Hl$ HeHEHEH=YNlH OlHNHEHHu&rHغlHNHHNHEHHe _][YSVWH lH M`NHH3WNH3INH5H=H ?NHLL3H(H;H5LH=]H ~ NHLL3H(H H _^[ YSH lH MM|HHSH9HH HtHH9tHH MH؀;HKn|HH [XSH lH LZM|HHH9'HH HtHH9tHH =MHH|HH [`XSH lH /LL{HHH9HH HtHH9tHH LHH{HH [XSUVWH(HKlH tLlH ?LHHHHHHYHH HtHH9tHH ?LHH LHHHHKH?H ǼKHHHt(?HHHH(_^][0WSUVWHHl$ HHHHe3HMPHMXHM`3HE8HE@HEHHE HE(HEHElH JRK;HHM %HM HHEPHAHEXHAHE`HHMP%H>H^U'HHHHE3LHPpu HuhHV :HMz%HMHHE8HAHE@HAHEHMHHM8Y%H>H^&HHHHE3LHPpuHuh*ffHyHHM8%ȅu fHM{IHNHM8$DHfH)HHMP$ȅf HMWHHMP$3HEhHex_^][SUVWH8Hi Hl$ Hm HHM8o$H8_^][SUVWH8Hi Hl$ Hm HHMP?$H8_^][TSUVWATAUAVHPHl$ HHeHElH bHIHt;He$ 3f LMu3q3H}H%$HHuHY>HLLA<$IHHPpIHwMHt9HE8HXI$I;LEHHs$H}tLuH HvH H2HHHu HE yA<$I?HHPpLIH~HuH DGHHH}?HHq"HQ>HLȅ HM9!HMHtH(9LHEfHE He0A^A]A\_^][SUVWATAUAVH0Hi Hl$ Hm HMHtH9LH0A^A]A\_^][RSUVWATH0IILHlH >FFHtFHtAH FHD$ LLIHr}H|HHH0A\_^][H3H0A\_^][@RSUVWATH0IILHlH EiFHtJHtEH `[FHHD$ LLIH|H/|HHH0A\_^][H3H0A\_^][QSUVWATH0LHiHq HY(H EHHD$ LLHH^|H{HIH0A\_^][HH0A\_^][`QSUWH`Hl$ HHe3HU HU(HU0HUHUHIHu39 8HHM HMHHE HAHE(HAHE03HHM 8HH5HtHE8*ffH=QHHM ȅu fHM&H&HM e 3HE8He@_][SUWH0Hi Hl$ Hm HHM - H0_][@PSUVWATH0Hl$ IDHHeH|ClH /DHlH CHH9H=ȅttH9HӾHH !CHHu3LHHrȅu29;HHEEt HHHHD3fHeA\_^][`OSUVWATH0HHD$ lH BICH!ȅt 3 ;rHD$ LD$ Hqȅr8H8HHcH BHq8Hk8E3HHjLeE~a3HcI;HT;E3E3HEȅt)HEH;scHLCqLD$ Hpȅu HE;|fH|$ tHD$ 8HL$ HP(9H BHD$ H0A\_^][BNSUVWHHHl$ HHelH 0AAHȅt 3DHEq8HHH}_HP?HLH>HN(H;u3"HuHu  fH(u>HHEfH?HLȅuHMHtH9LH]Ht;HS(HK @HHe(_^][MSUVWATAUHXHl$ HUxHHupHeHEHE:H8HHHLLmHIA}ILHH HtHH9tHH z@HLfI$Hu"H F@HHHI@H^HH;HHȅu#H^HH;LHHfHA}ILȅ1HUH k?HtH8HLHMx98HHHLLm LepH)A}ILHH HtHH9tHH J?HIt$HHu"H ?HHHH>I\$HH;HHȅu"I\$HH;LHHHqA}ILȅ1HU H ;>HtHJ8HLHe8A]A\_^][pJH8HD$ HIHu39LD$ 9HD$ H8@JSUVWATAUHHHl$ HeH4=lH =lH =HEHHH?H =HH|HH=ni=H LIIHH+H+;HH%HH}H?HL3sHcH;~Ml?IHqHH ׭HtHH9tHH =HغlH <HHϾI$HHuIM;HHAHHb;fI$9Ǿ8HHHeA^A]A\_^][̐GSH HٺlH l:';;HC8Ht@ 3Ʌt3HH =:Ht2H [0GSUVWATHPHl$ IHupHH}hHHeHEHElH 9:;HHH]@Ha;HLLLe A<$IT$8>HJȅgIT$8HIH8HLHHu(H >HLHLHtIH9tHI9HLE36hȅtgH]lH 89;HK8vȅt3 HH t9Ht3t?HUH HQ>HLȅ3HU(H ۩N9HEHtH&8HLHM 9KHupLH}hHH5gH]fH;HLȅCHMHtH9LHe0A\_^][DSVWH lH 7h8sg8H8HHcH SN8HFg8H8E3HHH~~3HcH;szHLf;|H 7HHH 7HHqlH 67H9LHHeHH _^[8DH8HD$ HIHu39LD$ iHD$ H8CSUVWH(IIHٺlH a67k0HKH6HK H6HK(HT$p6H(_^][̀CHÀCHA pCHA(`CH(HIHu39H(@CSVWH HHH+ȅt3HH eHHu 3H 6HHpHHHH`H_HH[HS0H.HS`HICpu f3H5H56HHt[HHjHHtFH {5HH8xH 4/5HLH-HHٸHH _^[BSUVWATAUAVH HHHtwHtr?HLMfE~[3HcI;saMlIHAdHuMHH^dHt 8HIHtHH)dA;|H A^A]A\_^][4pASUVWATAUAVHHl$ MHHHeHu3Hu3#3LLuIv HuHuHu Hu(HH}0Hu8Hu@HuHHuPHuX;IHHH]`HH;H!LMtH Mt IH;tE3fL]HeH;HLMtH HMt IH;tE3L]@H1H;HHtHH Ht HH;t3HH;HxLMt H ٣Mt IH;tE3L] DHH;H;LMtH Mt IH;tE3L](HH;HHtHH dHt HH;t3H}0HqH;H LMtH ,Mt IH;tE3L]8HAH;H LMtH Mt IH;tE3L]@HH;H[ LMtH Mt IH;tE3L]HHH;H# LMtH Mt IH;tE3L]PHH;H LMtH LMt IH;tE3L]X;HEH@uIV H ȅt3H 71LI˴LehA<$IIIV HR 3tCH ¡0HHHo H p0HHHlHIXH](H*`HHuhH dHtHH;t3DH=>HH HuHH>Le0IHH]@H ȅuH_HH>H3H=HسH]HH|_HH Ht HH;t3H=>HHFHHuHHH}PH ȅu,H y/HE3HH >HHd>HUXH\HU8HWH]HS I 3tHM`9 H@~ HHS H}H_ 3tBHLIl^uA<$HIw fA<$LƋI xHS H}H 3t@HLI ^uA<$HI .fPA<$LI LA<$HIHS H] H 3>HV(I]HHHD ȅt/H -HHڱA<$LËI CHHHȅt*H -HHA<$LËI HHepA^A]A\_^][p:SUVWH(HHـ;H~:33He 8HH(HvȅtHe;|ʸH(_^][:SH HH`\t;HHH \,3H [9SWH(8HHHHLH HMtHI9tIH ,LHHHLH1 Hغn,H 9DH H(_[@9SUVWATAUHHl$0HHHeHE8E0HEHEHEHE(HE #p+HE@HP Hȅt3zLE83HȅHE88H@3H=tPHE88HM84ȅt9HE88HM8%HH +HHHH HM8HtHHH?w D$ DE3H3Ʌf,^DDHDD;|Hy3E3EHLAT$+E3DHqHHu0mLLHbȅu H#)H HEEHHE@HH HMPI`HE)H HEHEHMHMHE3H;…tHH )H؋HDLËU0HM`~EHHHLP@HEP>)H HEHE(HM HM(HE 3H;…t HM_EHtHEPfHHfHehA]A\_^][06SUHxHl$ HHeHE8HE0(H H]8HM0HM8HE03H;…t 3uDHE@)H ?(H`HAHEHAHEzLHMHHE HAHE(HU H_HE@HC_HE@HeX][`5SUVWATAUAVAWHHl$0HHeHEEHHHLLeHHHlHHu @DžuLMLm(3H}H &J'HH09LEIoȅt HEn'LI 9HHH#&LIV ;H^HIV HILIIP@HIV H3tcI 9H{HHtIHH9aHHt/IV ;HHtIV HLIIP@HH2ȅtHHHHf,?_ DCDH/E03ɉM4ME3E3tVP+E3DHHHEHE8LM8LHȅtAE3DE0U4HLHH H\HE@EHADžV%H E3Ht\HTHEH}trH }$%HHK09IȅuHK09LEITHK09HȅuHK09LEH+HE[Lu@EHEHu LeLm(HH 3%HH #%HD$ LLNjUI[/HHH,D$ LL3HT[HCE3L;JLSLHGL;JLSHMt#H <##HH09MI-Ht#H ##HH09LHH "#HH09LEIȅtHE#3HeXA_A^A]A\_^][0SUVWHHHl$ HHeHg8HLHH]KH\;HLHHHLHHLȅtH}/fffffffH ;HLȅuHM1HMHtH9L3 HEHe(_^][SUVWH8Hi Hl$ Hm HMHtH9LH8_^][/SH H 7"HHH X!!HH0H!H [̀/SUWH0Hl$ HHH}0HeEHUH"HOHt HHPxHH AHtHH9tHH !HHOHb!HUH!fHe_][/SH H8H~ȅtHHsH9gHp!H3]H [̰.SVWH HHwHt$H Α HHLHHNVH _^[p.SUVWHHHHH3HH HmHHH m H5HH U HuHHH A H8HH(HjHzȅzHOmfH-HHtH9.t HH 8HH ߺHHHH HukH-HHHuHHXOHH}8H9HD$(D$ E3AHLSHHtH9.t HHW8HHtX;Hd3@ǀ}H AHX8@ljD$0HT$0H 4'LHH H HtHH9tHH H>HH EHH;HC HH=zHhzH3H9IHS 8HlHH $8HtuHH LA;IHtHŎHt HH;t3Hu9IHHt HH;t3ɐHD$(D$ E3AQHH_^][`+P+SUVWH8Hl$ HHH]@HeEHUHHsHHHH čHtHH9t H 7HHHUHhHe_^][**SUVWH(H HHLHH qHHHLIIHHH-TLH5H F1HLL3H?HHH(_^][ **UH0Hl$ HelHe])SWH(HH HHHHO+ȅuBH8HȅtHHdH9HOHWH(_[p)SH HA8A@u C8 uC?H [@)SUVWH8IHG<3;HKHt:H9L~'HKH 93LHH ֵH3HKHt:H9L~'HKH93LHH DHDKK CD$(L$ LHHyJH8_^][p(SWH(H=#gHgHHHHtgHH9H(_[(SWH(H=gHgHQHHHtgH]H93sH(_[̰'H(H `H@@H(̐'SH HHJHC0Ht@ 3ɅuHK0H9HA]H [@'A<@'t30't3 'A>'Q<'SH HzLIIuC=tHHH.HC=fH [&SVWH HH5zHzHmHH3{ȅzHkLIIȅuuv3lzH/H9Cu,_8H5;t/G?t'O8G8@u3G?tG?H _^[%SUVWATAUHXILHD$@HD$8HD$0}HEHbIL$(Xȅ3HIL$(LD$8HT$@HT$@INGH8HpHxH 61HHL3H"H CLH\$(HD$ E3LHILD$8II#GȅH\$8IEIPpHI];HULELL$0I3FHL$0aȅuZH\$0HMHPpHH@ȅu9HULLIEHޙt 3Ҁ;HfHXA]A\_^][ $SWH(IHC<3H~EHFFL'IHK(?HWHDE8HH9HkEC<H(_[̰#SWH(H AHHO@3;H TWHHHOHHH(_[`#`#SH HzLIIuC=u HDC=H [ #SUVWHXHl$ HH]hHH}`HeH3H&DHDH MHHH9B8HHH]XH;HLHH gHHNH?HW(9ȅuHNHHW(9DHQ;HLȅuHMHtH=9LH]hH HHJH};HHHuH>HLHغH 9HHH;HS(9VȅtI8HH28HH9H;HS(?HȅuHS(HHi>HLȅLHMHtHN9L@@8HHH] HucH);HLH?HW(>Hqȅu23H7Y8HH HW(HfDH;HLȅuHM HtH9LHM`AHe8_^][P H(LI@0Ht@ 3ɅuIH0H$HAHH( SUVWH(HHzH qzH <HH-AH :HLHH?HH2H(_^][̠SUVWATH@Hl$ HMPHeH BHHɋH}?8HHH]d@Hq;HLH>HߒLMt7HV A<$IL$ d3IY?IH fffH ;HLȅuHMHtH9LHUHMPX@He A\_^][̠SVWH kLII~ȅtSH5@H=H SHLL3H3H >LEIH _^[HH _^[ SWH(H 1Hx@HHu]LIIȅtAH -HHHH H9,?8HȒH(_[̠SH ڈ8HH [̀H(HHtB 3Ʌt3HH3F<HeA]A\_^][̀SVWH HG>HۯH:ȅtK=H/HHH9HH HHHG>DH5HH݇ȅtMH=HHHւHH u3҅€;H8HH _^[̠SH Hl83HdHH8H8HH9H [PSUVWATHHl$ HHHeHE83HMXHM`HMh3HE@HEHHEPHE HE(HEHEHwHHu"H AHH;HHnHO9zHw HHu"H /rHH/HH4HO 9@3H3H4LIHO(-~HHt;H:L%IHH;HupILI:LexHHM oHM HHEXHAHE`HAHEhHHMXKHE3;C(uLuMLO HH_3;HS :HMHMHHE@HAHEHHAHEP'HHM@LO E3HH3fH)HHM@ȅuH HM@@HHupLexHHHMXȅfHǚHMXvHUxHtHHK99HHUpHt HK9|9HK9h9H2HHtX?Gt3C8HK ?HW9LE8+ȅtHU8H@2HWHK(C?UDH1H~HH qHtHH9tHH HHȅu HH)1{8HH9HO1HA\_^][̰SUVWATAUAVAWHHl$0MLLLHeHEHEHEA<$It$I|$H qHHnL3HLZMHH LH\$(D$ E3LHIO~Lu MIIPpHI~8I\$H ~yLHD$ LLHI5L}(IN9HIH9]HHLLe0DH9A<$ILHH ʚHtHH9tHH HH}8H ,HHzHu@?HOH9KHOH9HHLLeHHA<$ILHH >HtHH9tHH vHIH54HHtHH;HH{$?HO0,HHtHW0;HzHt';Hx>HH{fffHA<$ILȅ%HUHH [nHEHtHƼ8HLLu L}(Le0H}8Hu@LIIPpHHHHH9|A}LHIffffffH1A<$ILȅHU0H mHtH:8HLHHHM 9r{8HHHHH}PZHۻ?HLHH ƖHtHH9tHH H;H{LCP>HH*fHy?HLȅuHUPH lEHtHY8HLHehA_A^A]A\_^][@ SWH8HHHD$(HD$ HȅHKH9ZHK9LD$(Hȅt}H|$(tuHD$(8HH0HT$(:HR8IzHHK 9LD$ HJH|$ t8HT$ H],HD$(8@Ht3C8HK(HC?H8_[P SH uHv8HvHH>HH 9L8HvHH nkt3Ҁ;HLH [ SUVWATAUAVH0Hl$ DLHeDu8HH9uHH}H?HLH>H^(Hȅt3H(Hu3tvAŅt5L5G*H jHMIHr>HH~9L5*H jvHMIH=>HH~fDH?HLȅ#HMHtH9LHeA^A]A\_^][à SUVWHHl$ HHHe3HEPHEXHE`3HE8HE@HEHHE HE(HEHEHȅt3sHHt;H 3HEhHHM %HM HHEPHAHEXHAHE`HHMPH؀;HKAHLu H]hHS :HMHMHHE8HAHE@HAHEHwHHM8H؀;Hst(#HHHHALHPp#HHHHE3LHPpu H]h#HHHM8=ȅkfHwHM8&H}hu'HHYHHMPȅfH7HMPHEhHex_^][̐SUVWATH@Hl$ LMhIHHuXHeIHu3H gHHH?H~H4HHHHH =HhHH?HHHHLP@H>H^H *LHI;{LeA<$HI.{q8HH91HH]PHa;HLLA8At+IH)HHtA<$IL$HHhDH ;HLȅuHMHtH9LHLH}HHuXHwzH]hHHHH>HN9HIH9HJzHN9@zHe A\_^][̐SUVWATHPHl$ MHUhHM`HeHEHu3.HE:HJ9HIH9HHHH}H?HLHH $HtHH9tHH dHؐHHHt(sHHHHAMHPp#KHHHHE3MHPpu H]#Ha?HLȅ;HUH [dHtHR8HLH}Hu2HHM`3$HHu2?H_H;HHH^HHHH>HcHHu BfH>HLH؀;HHHLȅuHM HtH]9LHMh9HI9wHe0A\_^][0H(HݜHHHHwLMtAC 3Ʌt3 IwwH(SWH(HHS(H"HtPH HH6wHS(HO[vt3GHwHK0HvH(_[`SUVWATAUHhHl$ HHeHEHEHu3<H %HHHHu;HKH9BHHHH} HӰ?HLHH HtHH9tHH HHHHt@ 3ɅuHH>LHHr;HS0>LH[H1?HLȅIHU H `nHtH"8HLH #HHXH}(k8HH9?HHu0LmH>HLLA<$A$tpIT$(A}LEIȅt?HUH4BfH yHHtIT$(;Ht?HHfH!>HLȅLHM0HtH9LHE(HeHA]A\_^][SUVWATH`Hl$0HHHeHEHEHEHȅt3LEHUHlHUHHu38HpHxH y_tHHژL3HeH ILH\$(HD$ E3LHIlMu 3BfHE A<$IL$9HIH9HHHH}(HЭ?HLHH HtHH9tHH HHHHLet(HHHHAMHPp#HHHHE3MHPpuH] /fffffffH?HLȅ,HU(H ]HtH8HLHE He0A\_^][SUVWATAUHHl$0LHHHeHE 3HM(HM0HM8HE@HMHMHHujHL#]HtIH9tHI[HHMHȅ.gHHt;H;fHEPHHMHMHHE(HAHE0HAHE8/HHM({LA;AC(uL]P'fffffHHHM(]ȅuHHM(LLmPMA}IuI}H ^\YHHL3HJLMH3H TLH\$(HD$ E3LHIiLeXMt3H}`A<$AD$c;Iui8HHHHH}hHuHfDH?HLHH HtHH9tHH |H؀;H iLt(HHHHALIPp#dHHHHE3LIPpuH]`,ffffH?HLȅ3HUhH kZHtH©8HLLmPLeXH}`A<$AD$cuA}AE(tHuaHHt;HK(ȅuHHt?HO(ȅtDLHH~LM LEHIHHȅt}H لHHXn;HHQnHU HLn?HHEnIL$9mI$IPpLM LHHI%mHexA]A\_^][`SUVWATAUAVH MMHHH '2HHmIHmIHmc8u3Hl>HHqmH_L5fHA;HHȅtH_HA;HHH_HCf;LHHZII^fHO(H:HH A^A]A\_^][`SUVWATAUAVAWHHl$@AىMLLLLLHeHE@HE83HE0HE(HEHEHE HEIL$(ȅt.D$(D$ DMII@IL$(LE8HU@dHU@IiLM3HM0kȅaA}IU8HkHE0HM0HغH H] HMHM HE3H;….HM0QHH HtHH9tHH HHuHHu4A}I}I]H HLHH3kHuH>Fcu A}AE(uDMIIHEPHN9HIH9BHHHEH6HE8HMLHH HtHH9tHH HؐHHHHu8t(HHHHALHPp#HHHHE3LHPpuH]P"HHE8HMLȅ0HUH T[HEH}tHQHE8HMLLEPMPD$8D$0D$(HHD$ LH]HHHH;HK9hiȅtCiȅu H;h$*iȅt5^8HU0H-iHO9HE(HO HW(9LE(EH}(tHE(8HM(趽3P8HH97H>t)HO9H臽H}(tHE(8HM(HmH5]8HH9 ;|HehA_A^A]A\_^][SUVWATH@Hl$ IH}`HHuXLHeHE3H]sHcH 0Hc HHfMu3MHHHHu3DexE|.?HOH9?D;}HOHHLAf?HOHHHhyHIuHu3|HEpHu3k8L`(3H NHHH9Ioȅt@?HOH9nHHHH}fDHq?HLHH |HtHH9tHH H@ƅt;HK0I2ȅtH]EHHIHȅtH]!H?HLȅcHUH ;QHtH 8HLH]Hu35HM`9HIHHHxHuX>HN9reHHe A\_^][  @SH AsIcH Hc HH@H zHtHeHHoHE3eHeLII;HHleIeHH/HE3;eH:eLII;HH$eEfeHHHE3dHdLII;HHdH [ SVWH0IHGA}I];6HH訷HHնHHEA}I];HHWHMHHMIÅuHEHEH(A]A\_^][`SUVWATHpHl$ HHHHHeEHt$HO3DWȅuHO9Hu3FHO9y8H T8HJHHufDHQ>HLLA<$A$HO9iIT$@8H豴ȅnI$9ֳHH}fH?HL8HHPH9HIH9藳HH} SH?HLH3H;t EGL%tHI $HHI $8H 9HH}(MH^?HLLH rMtHI9tIH L3L;tEH ?HLȅuHMHM{HH} NL%GsHI $#HkHI $8H9LHH}0H?HLH3H;t EL%qHI $HHI $8H09ٱHH}88HA?HLL3L;tE.ffffffH?HLȅuHM`HM8HtHݖ9LHH}0fH?HLȅHMzHH} HMaL%pHI $HHI $8H09ŰHH}@4@HI?HLL3L;t E&fDH?HLȅuHMUHM@HtH9LHH} fHi?HLȅHMUHMIHM HtH9LHH}fH?HLȅ HMUHMHtHH9LHHHufDH>HLȅ# HMHMHtH9L2EHePA\_^][SUVWATH0Hi Hl$ Hm HM(HtHL9LH0A\_^][SUVWATH0Hi Hl$ Hm HM8HtH89LH0A\_^][SUVWATH0Hi Hl$ Hm HM0HtH9LH0A\_^][SUVWATH0Hi Hl$ Hm HM@HtH9LH0A\_^][SUVWATH0Hi Hl$ Hm HM HtH9LH0A\_^][SUVWATH0Hi Hl$ Hm HMHtHx9LH0A\_^][SUVWATH0Hi Hl$ Hm HMHtHD9LH0A\_^][SWH(H3HtHHH nHt#8HWHH &mHHuHWHHuHH(_[̰SVWH IHHHȅ3HzLȅHNHjOȅHFHHC|HAHUu ;WHH~;HH茮H؀?AHHHHLHt.L8HlM8HhM8HVfHFHFH _^[̐̐̀pH(H%{H4NHH @Mt3H(@SUVWH(HrH HHHHu"H #SHHHHH9HH=?H ikHLHH2HAMH(_^][̰H(H#H(̠SUVWH(HrH YHHHHu"H cRHH3HHH9H> H=H hHLHHrH1QH(_^][SWHHHL$@HA IHHHD$(HD$(HD$8HD$8HD$0HD$HHL$0>3Ʌu3HD$0HD$8HD$8HD$ HD$ HHD$@HH@HGH_[pSVWHHHHL$`HA IQHD$0CD$4CD$8C D$HHc3Ht H1HD$(LHH:HHHD$ HH@HEHHĨ_^][0SWHH|$ HA IH赧HHD$({:LHGHCIHĨ_[SUVWHHHH|$ HA IHMHHD$(HH :LHGHCIHĨ_^][̀SWHHHL$ HA IHHD$(H93Ʌu3HD$ HH@HGHĨ_[SH@H3HD$0HL$0GL$0*ɋD$4*3HD$ HD$(HL$ hHHL$ HHHAHCHH@[̰SUVWH8Hl$ IHHeB8HOFHHK9萣HH]/HH;HL?LGL 78HHMAH;HLȅuHMHtH9LHe_^][SUVWH8Hl$ IHHeB8HEHHK9ТHH]/H;HL?LGL 8HHMAHq;HLȅuHMHtHe9LHe_^][PSWH(HH pHH(HOHH bHHHOHHQH(_[SVWH rH PHHHHu&H IbHHHH$@HH _^[̐SWH(HHHK9H赣}aHK9H蒠HK9>uAS@8HCH3H@ȅtHL@`HHIH(_[HH(_[SH HHK9ԡHK9Ƞ}HHH [HH [SUVWH8Hl$ IHHe?8HCHHK9PHH]/HH;HL?LGL 78HHMAH;HLȅuHMHtH9LHe_^][ SUVWATH HHHN9HH-L%s`I $2HLHH?HH:JH-I $HLHHɟHHJH-.I $HLHH蜟HHIH-I $HLHHoHHIHN9H,H A\_^][ SUVWATH HHHN9HH-L%c_I $"HLHH?HHJIH-I $HLHH蹞HH%IH-I $HLHH茞HHIH-I $HLHH_HHHHN9HԞH A\_^][ SUWH0Hl$ HHeHO9艝HH](H;HLHHHPhffHq;HLȅuHMHtH]9LHe_][̐̐SUVWH8Hl$ IHHe <8H?HHK9HH]/H;HL?LGL ߂8HHMAH;HLȅuHMHtH9LHe_^][ASUVWATAUAVH0Hl$ LHeH AD$AD$ #;8HFHHkHH9LHL-qkIEHHkkHH>LHL;HH3ۅL5?gIgIݿHH9?>IEHH!kHHLHL;HHv3ۅúgI調H9EIEHHjHHOLHL;HH3ɅAL$IEHHjHHLHL;HH3ɅAL$ IEHHgjHHLHL;HH褜3ۅúgIؾH9-EHjHHjLHHLLIIP@H趛LH>igIiH9DDH=igHhHHH:LIIP@HH؀?H=gH膼gHQH9:H _^[pSWH(H=agH4gHH9BH(_[0SH HgH gH 費H8@H [SWH(H=ЅgH裻gHnH9AH(_[SH HgH WgH "H9A%H [̐Q ̀SH HDH H ºH`H [PA @Q0SVWH H j>腺HHJH 9H`H2H5H=|@H 5T(HLL3H赔H7H _^[̰SWH(H=gHgH讹H9#@H(_[pSH HăgH 藹gH bH9A(H [@SWH(H=gHSgHH97H(_[SH H4gH gH ҸH9A$H [SUVWHHl$ HHHe3HEPHEXHE`3HE8HE@HEHHE HE(HEHEHnȅt33HHt;H藓 3HEhHHM HM HHEPHAHEXHAHE`HHMPђH؀;HKAHu H]hHS :HM藒HMHHE8HAHE@HAHEHwHHM8sH؀;Hst(HHHHALHPp#˓HHHHE3LHPpu H]h#HiPHHM8 ȅkfHGPHM8H}hu'HH)PHHMP͑ȅfHPHMP趑HEhHex_^][SVWH HHH R诶HHH =?HW(HH8}AHH8Z7ȅtIHL$ HغoH 3H;t3,8HT$ H*7IH8A]A\_^][̠SUWH@Hl$ HHeHEHt;He3H ZMHH:H}HHHHH]AHr;HLHH !HtHH9t H 述HЀ?H1Hyr;HLȅuHUH "!蕰HtHYr8HLHEHe _][̠SVWH HHH |LHHH6?t  @H6HH _^[PSUVWATH IHLHJHH 裯HBHHH舯HtHHxHHH]H~JHH SHtHH CHHH(HYJHH Ht!HH HHKHHyCHHHtHH֮HHHH,KHH 豮HtHH 衮HHH3HIHH zHtmHH jHHHRfHH MHH JNHHH'5;t H 5fHt1HYLHI-3HH?HH*HH A\_^][PSVWH IHH?HO 脈ȅtMHH H膭Hu 3fHw4HHXH赈3t3pHO(藟ȅu H9LHHH _^[HD@H IHH2HXLHH*2HW(He2HfH _^[pSWH(HHـ;HC8P@?H3HC8PAH3HS:R8H3HS:RH"Ht%HHJHHt?HOPHhfHl;HLȅuHMHtHk9LHEHe(_^][̐SH HڃsHcH Hc HHlf;3H0H0O;3H03H04;H0H0;H03H0H [!<W<s;HcH 5Hc HH3 f3̐H8HD$(D$ E3AiH8pH8HD$(D$`D$ =H8PSUVWATAUAVAWHXHl$0EEˆELHeIނȅe"8H%3H%ȅL5zI跧zI肧HH3"ȅzI耧H9HzI[H9HHH0zI2H93ۃsHcH Hc HHffL5&?HAHt HA8HpP'HLMu HL9\$(DDt$ LI-DAą AE 3;2HcfADEȃ'*HQHvHHHHLIHQL 較ȉM H7HU H H薃ȉMHUH HH M谥HL3H訥LǺH蘥MźH舥LI3KLEE3ɅAEAI,He(A_A^A]A\_^][蝥 @SWHHHH )H o踤H`HAHD$ HAHD$((LHL$ HHD$0HAHD$8LD$0HHHH_[SUVWH8IIHHu3i9+H3H 3H;t34HHD$ HCHD$(LLD$ HH+HHHH8_^][0SWHHt+H誣H )H m肣H`HAHD$ HAHD$('LHL$ HHD$0HAHD$8LD$0HHjHH_[̰H(LMtAA 3Ʌ @tIgfAQ ~Z3fD;sWHcADA&u5AEA A;}A;s8HcADA&tA9AI裀AA ;|IH((SUVWH(HڋH54*;3HH-+*3HUsHcH Hc HHfxHHUH)VHHU3H)73H3HU3H)3HHU3H)H(_^][(dG0s2HcH 1Hc HH f s/HcH .Hc HH3 fs(HcH "Hc HH3 3s+HcH %Hc HH3 3Ptu33@s2HcH ,Hc HH3 33ɋƒuƒuuжs2HcH ,Hc HH3 3̐3ɋƒuƒuu`SUVWH(HHHtAHnHEHu#H ;,HH&HHHNHWHH(_^][H(H賞H(HAH(Mt HI{H(SUVWATAUHHl$ HHHHHeHEHEHEHHFHH :2HH%H] ?H;H%HH$HyH$H/H$H -:谝LImyLe(HF8HH09yHHHH}0aH_?HLHH 7HtHH9tHH \H؀;HK0HS8 A<$LHIxDH)_?HLȅuHU0H HtHi_8HLLIT$I"H98HwHH]8Hu H^;HLH?HEHM(HW@9LE\xȅqIL$9HI09HU#ȅMHM9#HM9#L]A;HMH0!H9)wH J8śHHwH]@H9vHH]HH];HLLLmPHEXHE8HH@9|wHHLLe`@H]A<$ILHH 5HtHH9tHH *HA}I}@>H^0BwHHHHE3LHPpuHuX*ffH ]A<$ILȅaHU`H K 辚HEHtH\8HLH}XHtHHMPQH 4UHH!"HH]PHj;HS@?H"HM9HI@9H!HM@9HtH]HDH)\;HLȅCHMHHtH>\9LHE8HX@;HHHuHHHHHM@9tHH]h7H[;HLHM9HI@9H.!ffffffH[;HLȅuHMhHtH}[9LLHu H]8>HN09HU ffHZ;HLȅ$HM8HtH&[9LfDHHHHU \HexA]A\_^][H('Hu38HB fH(̠SH IHt8HH'H [̀SUVWATHPHl$ HHHeHEHEHEHGHtHrȅt3LEHUHHG8HH09sHHHH} @H Z?HLHH 1HtHH9tHH \H؀;Hs0Let(psHHHHAMHPp#HsHHHHE3MHPpufHs8Let(sHHHHAMHPp#rHHHHE3MHPpuH]($HY?HLȅ HM@,HU H `HtHX8HL3HE(He0A\_^][SUVWATH0Hi Hl$ Hm HU H  HEHtHtX8HLH0A\_^][@0HA SWH(IHHK;HKH/H(_[HAH(.H(A<Q<ЬH(H(̰SVWH HHu#JH@ ;HH `/KHHt=H5\?HHt)H8HHoȅuH8H@H=HHt]HH50HHޓHtAHHHɓH؀;HKxnȅt#脓H@ HCx#iH@ H _^[ðSH0HHtFH?H;DK D$ E3H_p3ɅtfA f HqHHH0[PSUVWATH DHH>HH *轒HhHHH}HHH [辒HL3H趒LH3ymHHHH˒HE3E3HH [#fHHHx>HHHHeHbD H4HHHHYHHH8HH lȅu5H8Hx H ͑HE3HH4mHHHH8HH(plȅuH8HP(HdHH A\_^][̰SUVWH(IALE3H}HmHHHHHveHr6HH ӉfHhHH?HHH$HHH|A}HIepH 6HH dHhHH?HH=H$HQHH H$9HdH(A]A\_^][0 PSUVWATAUAVAWHhHl$@MIHHEHe9dHH]HLLL]HL;HLHEHK?HLȅuGHt$8Ld$0Ll$(Lt$ MLHUHMHK;HLȅuHMHtHK9LHe(A_A^A]A\_^][`SUVWATAUH(HH 荈LI"c3ߋn ~yD$D;IcfLN=fȅtNuH>E3DËHReHH +HHHŎHIbA3;|t;>E3DËHdHH ؇HHHrHIbH 資HMHH*HH(A]A\_^][@SVWH HHH5, ;HHu3HLH Mt IH;tE3Mt:H HHHt HH;t3fH9HH _^[HnH HH g#ʆHHu2J;HKHȅt0HKHqHt HH;t3fHHH _^[HH _^[@SWH(HHHu3;HH ?!*Ht'8HiLZHHIH(_[HQH HH "Hu208HH0HHt HH;t3HHH(_[HH(_[̐SUVWH(HHHu3;HHEHt HH;t3HȅtH H9Hu28HH , Ht*8HN LGHHIH(_^][HcH5HHtOHH-c!HHM迄Ht2HHHM詄8HHxHHH(_^][H2H(_^][ÀSUVWH(HH3}H H؀>HHHHa HHHHkHl HHt*HHHHH?ȅtH HHtVH8HXH{HHȅtH 8HX0HNHHȅtH1Hȅt F~H(_^][`SWH8HHHtFH.H?DO D$ E3H+`3ɅtfA f H`H;HSAH^t:H HHȅt)Hq H ȅtC CfH8_[̰SUVWH8HH}H-HHtFH.H;DK D$ E3HY_3ɅtfA f H `HHH HH>HVAH^'HVAH]H HH ȅuHj HHȅt#HP Hȅt FH]HH) HH3HH bUHH HH߶ȅtHH 1$HH HHnȅtH HH聶ȅtH H/ȅt F~FH8_^][SUHhHl$ He3HE HE(HE0HEHE9HHM,[HMHHE HAHE(HAHE0HHM [8@uE8"fHPHHM Zȅu fHM%HnPHM ZE8HeH][SUH8Hi Hl$ Hm H8PHM ZH8][SUWH`Hl$ HHHe3HE HE(HE0HEHEHlZȅt3E8;HHMZHMHHE HAHE(HAHE0.HHM YH؀;HSHشȅt CE8HyOHHM YȅuH]OHM YE8He@_][0SUVWATAUH8HHHYȅt3)L-IM+f@?f@*>HHy\HDF C D+E33H[LH茳HH:*HA<$EL$ D$ E3IJ[3Ʌ3@Ņu&IM~f@*HI[p @AHH[H@;C(3Ʌt0S;|u%;t!+փH[ȅt H[H뼋C(3ɅH8A]A\_^][ЖSUVWH8HH}H(H=4)HH;E3E3HU[ȅuHHHYH؋s 3fD;HcDC?tC ;HcDC*DD+€;E3HYHZHHYHC ;snHcDC?u)D$ .HT$ H |HHZHHY(HH.YHW;BfHH8_^][|̠SWH(HHHVȅt H^|HHtG 3ɅftHH'HLHZfH(_[@SH HٺH /|HfB?fB*;HB3u#S{HP(AHY@ 3ɅH [SWH(H?HlV~A3fDHfY8HHZȅt HQYH+V;|H(_[̀SUVWATAUAVAWHXMMLLH=A}ILȅH6IH zHRHIH pzHIH \zHHH JzHH$HD$@H$L$H$Ht?H ȅt (t'H|$@H|$0Ht$(Ld$ LMIHH|$@;HK8Tȅt HwHC8HHHLMMIH$L$H$H$IHXA_A^A]A\_^][HoHeIH ByHqH:IH 'yHMtHI9$tIH -yLH3L$L$H$L$MIIH$L$L$HHXA_A^A]A\_^][HIH =xHuCIH |xHu/IH hxHuIH TxHfA<$IHH$H$H$ILgLMIHH$H$H$L$IHXA_A^A]A\_^][HMtHI9$tIH wL@A<$I$H=H$L$L$H$MMIH$L$L$H$HHXA_A^A]A\_^][HKIH %wH>HN8QȅtHH Hn8DH"HH *vvHHhHH}AHH UȅuNH"HHhHHH 2vHL3HvLH3PQHHH$轫HH0H=dL$L$H$MMIH$L$H$L$HHXA_A^A]A\_^][HHXA_A^A]A\_^][̀QpA`QPA@SVWH HHwHHu"H S6uHHOHHtHGH _^[HASUVWH(HHoHwHHu%H tHHfOHHtHH utHLHHHH(_^][̐SUVWATH`Hl$ ILHe3HM HM(HM0HMHMAD$IL$tH G*tHHNIL$Hs?HHMNHMHHE HAHE(HAHE0@HHM NIt$8HXH sHHH\z>HHfNHCHHM [NȅufHCHM HNHe@A\_^][̀SVWH0HH wr sHX8@ljD$ HT$ H j]sLHHVH0_^[0SH HٺH rrHH [SVWH H brHHHLI;H MHH MLLHHHغH q#rHH8HrH _^[̐SH HٺH \qqHP8HzHH P;rH [PSVWH HHu3UHݧHHu3AH HH qHt'HH qH؀>Nx;HHH _^[SUVWH(HHHu 3fDH= HH&qHtHHqHHcHH=4 HHpHt$HHpHHƦHfDH= HHpHtHHpHH諦H{H= HHpHt$HHqpHH膦HFfDH= HHFpHtHH6pHH+H H= HHpHt$HHpHH&HfDH=1 HHoHtHHoHH HH=$ HHoHtHHoHHƥHiHH roHtHH ^oHH賥H63H- HHM9oHtHHM(oHH荥HfHt>F(t?HHHtHIIEIHIIUhIHIHt_IHҡHHtJH k6mHHHxH WllH;LHHHIA}IM`H9HIHGȅA?AG(IM`9HIHIӢHHH lHHgH=>HHHGȅE8HHHL4/;HHMAHH &lHE3HH}H,?HH5HHHH0HHA>HItIM`9HIH/HHH=HHkHtlHHqkLA<$I(HI$H .YkHLHH谤I>HHA>HIA>INxHtA}IU`:HRX9f3}A}IMX9HH`H5HHjHHHjHH.t0A>I~HH ajHH@?HHEf>HNH9qFHHHH] \H-;HLHLHtIH9tHI(jHIHtA>INH9HDDH,;HLȅuHMLLuL}?HH iHt+H ziHHQA>INH9HD}A}IEX8HHHt HPp3;PIHe8A_A^A]A\_^][SUVWATAUAVAWH8Hi Hl$ Hm HU H !iHEHtH+8HLH8A_A^A]A\_^][`SUVWATAUAVH LHHu3P>HN0 Hu38H HahHHu3?HNpHVHNPCȅtHHHHHNHVXHHHH,HNPIHHuHHHH gHt_HH gHL5;HAHtH~HAȅt'}H8HHHf}Hd8HhH>fH )H k0fH`HAHD$ HAHD$(OLHL$ HHD$@HAHD$HLD$@HHHH}H8HHeH )H /zeH`HAHD$0HAHD$8LHL$0HHD$PHAHD$XLD$PHHbHH}H18HP8H*HEHHHHEHHH虞HH dH؀>HH?ȅt;HHH;HHH蘞HHlHH۝HH?H=HHH?HHHHHHHHHI>ȅt>Lf(>HN IcH`A\_^][̰~SWH(:HRH LcHHtK;HH cHHt-?HEHH)H8HHH(_[@~SWH(HHu3.;HK0ʑHHu3HS0?HHH(_[~SUVWH(HHHHH?HH5jHHbHtjHHHb8HH=ȅuGHHHbH؀;HKh=ȅu!HK9fA f L@HHx.#$bHX ?HO8=ȅt;H-HUH=ȅu#HU8fA f H?HH_8>HnHM<ȅt HHaHHu&H OaHHHHjfHgH HH }aHu H aHHHH(H'HH @aLHHIH(_^][HH(_^][|SWH(HHu3t;HK0zHu3_HH `HHu3DHH?HHH]KPH貔HSHHHH(_[̀{SWH(HHu3;HK0׎Hu3lHH /`HHu3QHS0?HHHHHCHKXHHSHHHH(_[zSUVWHHHl$ HeHEH _HH?HWHH k_HHw;HHH}3H>ȅ+HHLLE3H>:ȅthHE8HM/:ȅtQHHLHHHHLHHHHLHHH;H"HH@Ht-3HrȅtHHLHH;HHu7HHH9HH b^HHHMHtH 9LeHWH=H]HH SH]H;HH]HH?HH5H]Ht8HHtHH9tHH]HȀ9sHH谓HH H3]HH萓?3HfH;HH= H\Ht:HHtHH9tHH\Hf9HHHH \HH;3HfHe(_^][̠wSWH(HHu3;HK0׊HHu3HS0?HHHH6ȅuHHHH=Ch9ȅuKhHCp9ȅuKpHHS`HHH(_[vSWH(HHu3V;HK0 Hu3AHH b[HHu3&HS0?H.KD6HsHH(_[pvSVWH HHHu3 ;HK0胉Hu3H HZHHu3HS0?HHHHHHRKlH觎HS`HzHKPY5ȅu"HKP>LFA3HHHKX'5ȅu"HKX>LFE33jHH3HKh諸HHHH _^[PuSUVWATAUHHHl$ LLehHH]`HeHEHu3;HK05Hu3HH YHH}Hu3i?H%H跍HHHHHQHSpH$SAHoHK`3ȅu%HK`A<$3MD$A6HH;HKh3ȅu(HKhA<$3MD$E3?HHW;HKP94HHLLmHA}ILHL:HtIH9tHIrXHI7HHt_?H09H2;u<>HHH\HHHH,ffffHA}ILȅ9HUH kWHtH8HLLe`A<$A$IL$XH9HIHC2ȅhIL$X9HIHHUhsHH A,WHHH}n8HH؀>HCL;HHMA?HH>L-w3HAU3HkHlHHtHHHAUHQ>HHtH?HH H>HHt@L-A<$IAUH)1ȅuHHIAU;HKHV?HH>H!HYHHH}?H0921H0931H :HUHHl;HHYH Hd0ȅuAH&HH|L>H3HHlHHjL93H8HL;8HHMA?HHe;HHHHHH THH'H=IH/ȅuI;HKHhTI$I;HK0HLTH}?HH13CXH褍HHH}A<$A$Ȳ?HbHHe(A]A\_^][poSUVWATAUHXHl$ LLexHH}pHeHEHu3H SHH)Hu?HW0>HzHHHH3ۉ]h?HOH9.H=HH +FSLM"t0>HH 0SHH?HH-A}IMH9/HHHH] hH;HLHLHtIH9tHIRHȐI蘈Ht#>H9H.-ffffffH;HLȅ{HU H ~RHEHtH~8HLH}pHu]Lex]ff?HGH8HHHtHPp3;pHHe8A]A\_^][@mSUVWATAUAVHpHl$ HHHe3HE HE(HE0HEHEbH PQLI$xHHu8L5L-H h;QHMM3H+HH QI$x?Hz/H QHH,Hu83ۉ]@H+/8HP:HM+HMHHE HAHE(HAHE0+HHM g+8HP >LH-ffH٩HHM M+ȅuHHM <+E@X]@HHu8?Hu+;H>H*HcH z3PHH+8E3HHo.HfHePA^A]A\_^][pkSUVWATAUAVAWHHl$ H8LL0He3HEXHE`HEh3HE@HEHHEPHEpHE(HE0HEHEH {OLI-Lux3ۉI-8HP:HM()HM(HHEXHAHE`HAHEhzHHMX)H?HGHt@ 3ɅuGHH0?HA>H nNHL3HNLL3I-HqHHMX])ȅhfHOHMXF)XL0Lux@A?It);HeHA>I+I^HHHMH NHHHc,H MLLII,3ۉ-LcL;NlA}Me HH0I}A>HAHHMHM3HMLǺH}MLL3I+HH0EHUH WzMHH8HH !MHM3HMLǺH MLL3HHR+HE3;AILI/HHFH;HL HHLP@HIEIMP@HA>H ^LHL3HVLLǺHFLLM3I*H :LHH*HH iKHHq*H?H_H L7'HHHHH;HH(H_H 'HHHHH;HH'H_)HH;HH'H_H U&HHHHH;HH'H_H 'r&HHHHH;HHL'3ۉI )8HP:HMj%HMHHE@HAHEHHAHEPmHHM@I%LA;ICHt@ 3Ʌfu7?H_A;IK(HH;HH&fHHHM@$ȅufH߬HM@$XL0LuxHHfDA?I$;3?G_G\G]H8HO ~IH IHIIMP@L3HIHLHHLH؀;HK9'ȅH x;ILI'LHjHA<$Ir&HK9%HHLLH) A}ILHH BHtHH9tHH HHHH0?HA<$H -HHL3HHLL3I&H A}ILȅaHH [HHtHw 8HL@HB@pHHLIIP@HH$HH _GHHHl&HTHHA_A^A]A\_^][H0c cSUVWATAUHHl$@He3HE83HE 3HM3HE3HE3HE03HE(%LIIHHpHE3%HH}@H_HHLHtIH9tHIFHH2H*$HH]H3HE8HM8 !A`V%HE H"ȅHo!HE83oHcH;sqHLU!HEHE HEHEHEHUHH?H#HMH H?H#3H;tHEHE HG;|iFHE8HE0HE HE(HU0HH?H#HM(H H?H#3H;Hu@H^H EHHJ$H}P3EXHcH;-H\AAH sEHDl$ EEHHB Hu`HH ƞHt H9tH,E?HHHM`HtHL9LEXEXHu@H}PHN;PH]HHHE{H]HHt#Ht#HH H9HD$8HD$0HD$(HD$ AE3:#H cHDHexA]A\_^][D_SUVWATH0AHHHL H DH>LF 3HDLFHCF4u H]L HILHCLF(HCF0D$ HT$ H CLHCDEuHL HCLHaC;LM3H!H0A\_^][^SUVWATH0LHHIH0DD$ HT$ H 8CH}H BHM3HBLǺHBLL3H !H0A\_^][p^H$9A$:H $B ;} ;~3H0^HA0^SVWH IIHHKAHK HAHKHAD$`C(H _^[]HA]HA]HA ]A(]SVWH IIHHK7AHK H+AHKHAD$`C(H _^[̀]SUVWATAUAVAWHxHl$0AMLLHeHHA IkH3H HDž LcHDž H(MtiLmII.ALIk؋jKL HƵIEXE3M@HH(Hc0D0D0LHtPIINE3 HH؉\$ E3L3HLcB@HDž LcHDž HDžLIIHDž 0HtHDHI$HHHH@HA0H ~ H(dfHHA_A^A]A\_^][̐[SUHHl$ HHeHMHA IHHDžHӹHHDžHEH#HDžH"HEHHH@HAHH~ H@H][ZSUVWHHl$ AHHHeHMHA IHHDžHDžH׹HHDžLcHDžHEHH/HDžH"HEHHH@HAHH~HH_^][YSUVWATAUHHl$0IIDLHeHDžHDžHMHA IH3HIչ LLHDžIcHDžHtHHHfHDžE3HtHLIHDž HcHDžHEHL$ LIHDžf!HEHHH@HAH~ HDHA]A\_^][pXSWHHHL$ HA IEHHD$(H3Ʌu3HD$ HH@HGHĨ_[XSH HHKȅu$HCHt@ 3Ʌ3H [WHAWHA̰WSWH(Hٺ#:Hx HȅuzH6H;E3E3HBȅtXHHHtRH H;E3E3Hȅt0DC AE3ɺHXH`H HSHHH(_[WSUVWATAUH(HHHH 9HHt ?HӿHH 9HHH 9HHH-5?HU3HȅuHU8H#A9H@ LfHI69HHNH!9HȅH-HUL-HIM9HHUHHtIEH9EtHIM9H躳H 88LIH}H&HH 8H3Hȅt}HHI\8HHLiHtIH9tHIq8HIP9HH Ht HH;t3HN7Hȅu]HtX;H3'ȅt#7H@ H9HNH7HHN7HXȅH=HH7HHHo7HH-?HHu3HH H@7HHu6H09~#H093LH H7HHH=ʺ;HHHHH *6HHHHWHN6HWHN6HH 66H;H3ȅt#A6H@ H9HNH$6H HtHH9tHH E6HfHHHt HH;t3KmHNH5H(A]A\_^][RSUVWATH HHȅt3Dg E~g3A;HcfLOȅu1O ;swHcDG-t;sfHcDG_uuu ukG ;|tt+?E3DŋH73H A\_^][@s5RH1lHQH(>LIIu(H 34ƀH lH(HH(ðQH(LIIu8H 3Q4LAtAƃHk3H(HH(`QSH %8H!HH/HLH MtHI9tIH 3LHHHgLHHغnz3H 9H`H [PSUWH0Hl$ و]0He<8H09 DEu[lH }283aHHH9HH cHtHH9tHH 3HHaYlH "22aHHnH9HH HtHH9tHH 2HHa;H HH}1H?HLH=8H09H H?HLȅuHMHtH9LE0u 8H0iHHaHe_][@OSUVWATAUH(L-EAULII3ۅúH 01 iAUHH5hL%H-mHM\1HML3H ?HHʫAUHH5hHM#1HML3H ?HHH(A]A\_^][`NPNSWH(H=0zH0HH30H3w0H3i0zHd0ƀHHH?0H(_[MSUVWATAUAVH@Hl$ DHHeH=k/zH0HZzH/HHHHu"H g/HH' HH/AązH ./H9[8HHHH9 ;H HHu H>HLH?Lg@L5.zI/LIzI#/f.A<$EL$ E3IZ~PA<$ED$ D+E3I Lf.;DK E3H"~P;DC D+E3H HAHI 3Ʌu4?t&3H#I9H fH>HLȅHMvH9i HH](H;HL8HH;HLȅuHMHtHm9LHe A^A]A\_^][SUVWATAUAVH0Hi Hl$ Hm HMHtH9LH0A^A]A\_^][SUVWATAUAVH0Hi Hl$ Hm HMHtH9LH0A^A]A\_^][̰JSVWH HHzH 7,,?w DE3f.H* ~P+E3DH H;s DE3f.H ~P+E3DH HAHH3ɅH _^[JSUVWH(HH-+zHM=,?H_@zHM,HH ȅtH d@HH(_^][HH(_^][̠ISUVWHHHl$ HHeH=H}EHUHa,H5*zH+zHh+HHHtHHPxHDH HtHH9tHH q+HHH+HUH+He(_^][HSUVWHHHl$ HHeHUH]EHUH+H5**zH*zH*HHHFHH LHtHH9t H *HHt*HUH@+He(_^][PHSH H)zH W*zH "*HH [ HSWH(HH=`)zH*zH)HH)H(_[GSUVWATH H)zH )zH )HHH3ȅH >)HHVHHS)HHt'H?H E`)HHLHHMUH9VzH e( )HL%`H-CH ̔(HLM3H|?HH.THH A\_^][FSUVWATAUAVAWHHl$0HeHEHEHE(HE HE0HE8HEH5'zHX(zHK(zH(HH3,ȅu'zH(LIIȅu3H 0'HHH}@H 'HHo;3HiHcH`HH\HEzH{'zHF'H9R8HS8HHH]HH;HLHH}PH?HO@LE HU(NH5/&zH&zH&H9nS8LEHU(HHM9HMHU wUH8HHX9HHHH]XH0;HLLH MtHI9tIH [&LMOA;HEISH8E3LeHHHt9LELeME3A<$IL$X9HHLLm`HA}ILHH |HtHH9tHH %HHH ny%HtA7?L}H_PI$IDt$ LLHIA]fH A}ILȅWHU`H ˕>%HE0HtH8HLH}PH]XH;HLȅTHUXH k$HE8HtH8HLH]HffffH);HLȅ'HMHHtH>9LHEHHM L]@IIP@HexA_A^A]A\_^][ BSUVWATAUAVAWHhHl$0MMHHHeHEHEzH "#HHtHuH=yHH#HHHz#H؀;HKH9HKH9|HHHH]PH9;HLHH HtHH9t H /#HHt@|$ MMHZ@H;HLȅuHM0H=HH"HHH"H؀;HKH9HKH9HHHH] OHp;HLHH HtHH9t H N"HHt@|$ MMH ZH;HLȅuHM7H=0HH!HHH!HHHLGpHHHoȅu HLeHHHHtQL=S;HAHtSUVWATAUAVAWHHl$@MIHEHHHEHeHEzH H#VHp HHHFȅuHHHWHKP9~GHKPH=93HHHȅuHKP93HHH;HKP9HHLLe DHA<$ILHH zHtHH9tHH HHFH=ϺHHlH+HHXHHHLCpH=#HHȅu HLoHHHHt[HHE(?HHtCHHE(H٦HU08HHȅuHHE(8HHE0LHtF 3Ʌt&;HCPDt$(HD$ MMHUHM U+;HCPDt$0HD$(Ll$ LMHUHMTfHaA<$ILȅYHU H ˍ>HtH:8HLHeHA_A^A]A\_^][;SUVWATAUAVAWH(IMLLHzH zH kHHdȅu-HQȅuH>ȅH)HH z HHhHHHHLIHhHHHLIHhHHHI $HkH9I<$H\L(H$Hu HH;HH?LIH;H>LAHHSȅt$V HD@ A+AHHHHLH'L$ȅI4$HH8H oHM3HLHMƺHLHLCMH{MźHkL$HVLH3HHHI4$HH8H HM3HLHMƺHLHMźHL$HLH3lHHHI $HH(A_A^A]A\_^][̠7SUVWATAUAVAWH(MMLHHmzH zH LI$ȅuI$ȅtkHHH HHhHHI$HLIHhHI$H]HMH*H9>H}HH0H$Hu HH;HH?LHHD$AÅHuHH8H HM3HM$HMƺHM$HLeMHMźHLH3PHHHHuHAH8H EHM3H=M$H(MƺHM$HMźHLH3HHHHMHH(A_A^A]A\_^][4SUVWATHHl$ He3HHH3HEpHExH3HEXHE`HEhHE@HEHHE(HE0HEH5fzHzH zHHHH3ȅu!zHH9#AHuzHH9@8HLMzH`HHHu$H }PHHHHfHHHu"H HHHHHHHu#H !HHHHA<$IHHH;HLHȀ9H9HHH;HLHH9ƅHIP9HIH9kHH@Hq;HL8Hx(HH0t(/HHHHALHPp#HHHHE3LHPpuƅ,ffffH;HLȅSHHtH9LH8HHP9HIH9\HHHHy?HLH؀;HK(HHA3҅HJfffH)?HLȅuHM3HCH;3HkzH BH9H HH;HLȅHHtH9LHfH9;HLȅ3HMHH:HM@dHM@HHHAHHAHHH78HaHHH*ȅuHHHH9%DHH:HM(HM(HHEpHAHExHAH4HHMpH؀;H3҅HfDHHHMpmȅuHխHMp\@HH9jHH:3HEHEHE HM7HMHHEXHAHE`HAHEh2fH]XH[HEHMbHUH&BfDHMXȅuHMXۙHH9əHA\_^][SUVWATH0Hi Hl$ Hm HHtH9LH0A\_^][SUVWATH0Hi Hl$ Hm HHtH9LH0A\_^][SUVWATH0Hi Hl$ Hm HHtH9LH0A\_^][SUVWATH0Hi Hl$ Hm HHtHY9LH0A\_^][SUVWATH0Hi Hl$ Hm HΫHZH0A\_^][SUVWATH0Hi Hl$ Hm HHMp&H0A\_^][SUVWATH0Hi Hl$ Hm HMX(H0A\_^][p,SVWH HH5, zH zH HHHt6;H@;t@HוH9HUH _^[+SUVWH8HHH- zHMM zHM? ?HO(H"HA/3@@HDzHME HHHtb H 3H;u=@ƅu5HD$ 3HL$ HT$ H>H9HH8_^][+SUVWATAUHHHl$ HH]hHezH C ;HK9|HH]+H;HLHCfffffffH;HLȅuHMHtH9LHMh9HI9HH}qHa?HLHE3L% zI $ >H^@zI $F HHOȅt AHLCffffH?HLȅsHMHtH9LHe(A]A\_^][̐)SUWHHl$ HHHe3HM@HMH3HMPHMXHM`HMhHMpHExHMHM0HM8HMHMH { HHHHHMHMHHEPHAHEXHAHE`HAHEhHA HEp`LHUPHMHMHHE@HAHEHHfHHM@Hu%HHM@y?HHSfffH1HHMPUȅuHHMPD@H9HHH;HHHh;HȅuHH zy HtH 8HLfH_]['H(H(̰'SUVWHHl$ HHe3HE@HEH3HEPHEXHE`HEhHEpHEHE0HE8HEHE:HMHMHHEPHAHEXHAHE`HAHEhHA HEp\LHUPHMHMHHE@HAHEHH5HHM@HHHM@LHHafHaHHMPȅuHEHMPtfH_^][̐&SUVWATH IMHHHHH aHhHHHH x'HHu3HHHHHu3H w4HL3H,LźHMĺH LH3fHHH HhHHHH 8xcHHu3^*HHHHHu3>H wvHL3HnMĺH^LH3!H A\_^][%SUVWH(HHO9((HHt?H-d>H PHLHH>H%HHH(_^][HH(_^][̐$SUVWATAUAVHHl$0IHLLHeIL$HtHu{>FHt#HVLFLNHF09HD$ ZMHF@HHV LF(E3I=HH v&HHHH HHHHLH ڠMtHI9EtIH LHHXMHIH wHIH cL58HAHHHH 7HH 8HHd?H[3HE0HE8HE@HEHD$ fWofWHM0)L]0IHEICHEICHE ICHE(HUHHV@H;HAHHL3fIL$>HVLFLN9Ll$ ƍxLH>H^ H~(HN83hȅuL^8IIP@f3LLHI;Hu&IL$>HVLFLN9HD$  fHePA^A]A\_^][!H(HI Ht 9H(̠!SVWH Hy?HwHt$H ZsuHHLHHNVH _^[`!UH0Hl$ HM He9$Ht 8HY#HE HH9|fHe] !SUVWATAUH(HHgH gH HHHu+HUH&L-gIMHHu HVHgIM_H?HL%9H )HMHHHOHL%u9H HMHHHOHH>L%"9H {qHMHH?HHVH>H5$9H %HLHHW?HH("HH58H zKUHLHH?HH 8IMHHHuӊHHH(A]A\_^][@H(A8A@tA(u8fH( HA SH HHS:3Ʌu H;HCH [SVWH HHHO H59;HHO 9ȅuG(tG(fH _^[̐H(HI Ht 9ʉH(pSVWH HH5W7H `oHLHHzH|9L9IH _^[HH _^[ SUVWATAUAVHL3HD$(HD$0HD$8HD$@HD$HHD$PHD$XHD$`HD$hHD$pHD$xH 4/HH8Ml$HIIU:HL$(8IL$0LwHT$(I56ID$ HHgH gH HIl$HzHuI]L57H oHMHH6>HH7HuI]L57H ٚ4HMHH>HHHuI]H-7H HLHH>HHчs@ ~IL$ Ht 99SwHH55H HLIHd?HH-wH &HHeIt$HHEH>H-4L-lIM;HLIH?HH#H3HD$ AE33HL$ ;HT$ HH9H=p4IMHLIHHwHĀA^A]A\_^][PA8IPHL@`IH@SUVWATAUH(HFL-uAUHH-4L%AI $0HLHH?HHxxAUHH-3I $HLHH?HHquFH(A]A\_^][̠SUVWATAUH(HFL-&uAUHH-P3L%I $HLHHG?HH|AUHH-23I $IHLHH?HHY|FH(A]A\_^][H2HA8IPHL@hIHSWH(H9t8HwH3Htȅt);HH؀?HHHyw3H(_[̀̀H(H#H(pA`QPHA@ 30H  3  3H(HH(H(&H(SWH(HHHHHHHzH(_[̠H̐SUVWH(HHH#H>HV}HtHN3ȅt3HV}HgHN0ȅt3HV0HKHNPȅt3HVPH2HNHȅt3HVHHVXHHN ȅu-H~ H gHE3HHHH߁HV(H܁HHMHNȅtHN-HHH(_^][PSVWH HHu3r?HO@ȅt3[3HO8ȅu$H_8H fHE3HHcH@H }HLHH&HH _^[SUVWH(HHHZȅt3H hHH'sHNH#Hȅu)H f0HE3HHHNHHNHH00HH(_^][HH(_^][SUVWH8Hl$ HHU@HeHu3sHE:HJ8HR@-HEH5H}HHpHHu#HpHH|};HHHU@H-HHe_^][pSVWH HH HtH۸9LHHt$H dHHLHHNVH _^[SUVWH8Hl$ HHH]@HeEHUHHHHHH dHtHH9t H tHАH(HUHHe_^][̐SUWH0Hl$ HHH}0HeEHUHNHHt HHPxHH ncHtHH9tHH HHHHUHHe_][SVWH IHHH}H H8HH{HHvH _^[H(H HtH9LH(̠H(H0H(̐H0̐SVWH HHH(HH3t HHuLIH}fH _^[@H(0SVWH HHH HH3t HHL.IH|fH _^[SWH(HHHH`|H QHHt8H H*HHzH(_[̐SWH(HHH{HtC 3ɅfEH H)H(_[@SWH(HHH{H0HH(_[H(^{H(SUVWH8Hl$ HHH]@HeEHUHHHHHH !`HtHH9t H HАHHHUHHe_^][̀SUWH0Hl$ HHH}0HeEHUHnHHt HHPxHH _HtHH9tHH HHHHUH(He_][H(&zH(SH HHHuHyHuHHwfH [̰̰SUVWHHHHD$0H ȅ,wh8Hk3Hkȅ3H-zHMzHMHH3hȅtrzHMH9HtPzHMoH98LL$0AHHxLMtA;ICPHt8Hp(H Ht$(D$ E3E3!xHHt$H ]HHLHHNVHH_^][PH PH0HuH(@SVWH HH3H;tH HVHt8HHH|HHtoH}HHHH;t3MH0HuH(H ]!Hu2$Lɰ8HHMAu22H _^[p`SUVWH8Hl$ HHH]@HeEHUHHsHHHH [HtHH9t H WHH HUHHe_^][ SUWH0Hl$ HHH}0HeEHUH.HOHt HHPxHH Y[HtHH9tHH HHOHrHUHfHe_][` SUVWH8I؀;C H{H [nHHHbkHHPH9\kHHH-:HEH9AȅuHHH}] DCHD$ DHP+E3DHHHH? HHHHLHE3D3HHHu3"fHKLH#Hvȅt*HHHnHMeLHH#H@ fH8_^][` SWH(k8HrH XHAHHH(_[ SVWH II*q8LLHMrH _^[ H(p8H*rH( H(naLIIH(̰ SHH3HD$ HD$(HD$0HD$8HD$@HD$HHD$PHD$XHD$`HD$hHD$pHL$ z LCHT$ HvHHĀ[@ SVWH HHwHt$H ^VyHHLHHNVH _^[ SUWH@Hl$ IHHEHHeHEHEMtHt8IHHE3Ht8H}`LHHHH}`HuHMUHHUHt HH;t3HuHtHM7H}1HGH8HHHEHM9(HM.HEHHMH;t Ht9NHEHe _][SUWH0Hi Hl$ Hm HEHHMH;t Ht9H0_][SUVWATAUAVAWHLLAX3HL$8fD$4AX3HL$8|H^LIILLIIHH|$8H$LIIHGLd$8Ld$@HH$HHA<$At$ ^HD$ DDIPDD+E3I$HG HAH8H'HHD$ DDIP+E3DIHnLIIP@LH$HHH\HHQHHHCHHH>躾HHHHLHE3D3H\HHHH$HHHnH 9IǾHH=LL%3I$HHL$ E3HILH5RMtHI9tIHL@H$L](HLI$HHL$ E3HI0LMtHI9tIHuLfL]8HLI$HHL$ E3HILMtHI9tIH-LL]0HgLL|$ E3HIHHtHH9tHHH؋C fCfD$4HD$43ɃRu'D$0RHT$0H QHH褾HHH6HD$PH\$8[LIIHCPL}HT$8IIHĨA_A^A]A\_^][H(>[LIIH(SUVWH8Hl$ HHH]@HeEHUHHsHHH *Ht H9tHHHRHUHfHe_^][`SUWH0Hl$ HHH}0HeEHUH~HOHt HHPxHH *HtH9 t HHHOHHUHDHe_][SWH(Hٺ-H HH9褾~0H9虾HH&H9wH(_[̀SH HLIMtIALHIIH [H#-H [fH9H$H [0SVWH -H (HHHHuHH tHHHHH HH赽HH^HH _^[̰SUVWATAUAVAWHxHl$0HeyXLIIHغnH 9AHHHMHmH9AHHu L%VLe(I$HEH=MH}0HUH>LHH蔼HHD(E1I$HE HU HLHHJ@HىHH HHhHHLHHHhHLHHHhHLA|pHE(HHEHUHM0H LHH58H ѥHH9IvgtH9E3IdgHgH hgH 3HHt5H XsKHH(?H\$ MMIHe HMXHM HtH9LHMvHMHtH͟9LHeHA_A^A]A\_^][SUVWATAUAVAWHHHi0Hl$0Hm0HM HtH|9LHHA_A^A]A\_^][SUVWATAUAVAWHHHi0Hl$0Hm0HMHtH<9LHHA_A^A]A\_^][̀SUVWH(HBHcH Hc HHH wMtHI9tIH LHhIHH;H-H HsHLHHZ?HHse;H 9wMtHI9tIH LHpI/ƆxH(_^][oSUVWATAUHhHl$ HHHeCTLIIHغnH 9H訵LLenH 9H耵HHu#rH@ HE MtHuH!H0H HEL-IHUIMA<$LHI1HIMu}HDžH0EHH>HڴHHu(HuHHHM HHA<$I褴HH}0HuHaHHM DHYH#oL@ >HHuHH5KHHtHH9tHHHL%I$HH蚲ȅtL% I$HH葱ȅt:I$H?H舱LMtHI9tIH-LL] L%уI$HH:ȅtHHhHHHHHHhHLHHHhHLHgH gH ]HHt@H uuHHr ?H\$ LMIH[HMu#HMjHMHtHF9LHe(A]A\_^][SUVWATAUHHHi0Hl$0Hm0HMHtH9LHHA]A\_^][SUVWATAUHHHi0Hl$0Hm0HMHtHŕ9LHHA]A\_^][@SVWH KHH~HH -HHhHHHHE3E3HLHHU~HHhHLAH3\H _^[̰SVWH Hxu=ƆxH}HH @HAHHHH[H _^[`SUVWH(HBHcH Hc HHH mMtHI9tIH NLHhIsH lMtHI9tIH LHpIHH;H- H uhHLHH自?HHZƆxH(_^][5̀SH HHZL HIH [HH [PHA@H(HH(0HA H(HH(HASUVWATH0Hl$ HHM@HeHE3H蔬ȅt 3|fDHEH |HXHt9LEH,H}>HF3H=t@Hȅt1HHH hHHHPHP HHHH fHEH}u3H LI$XHHu"H +jfHH#HH(I$X9LEHH}u3IH]@HKȅu,HMHS93OȅtHMHS9F3HeA\_^][0H(HH( SUWH@Hl$ HHeHSHHHKH~9諦HH}*H?HLHH}HtHE"fHY?HLȅuHM0HMHtH59L3 HEHe _][SUWH0Hi Hl$ Hm HMHtH9LH0_][ SH IE3Lc3诪HHCLIHAPH [H(IBHHJRH(SUVWATAUH8IEAHL-QeE3ME3;HE3ME3H'L$HFLIJT$(Dd$ DHARH8A]A\_^][pA0`Q0PH(NEH(@SWH(H ~HHSPHt=H .Ht,H{P?HOHt9#UHGHKP3H(_[SUVWATH0HwHFHH 9fH HH_PH3HtCH;tH 9 3HIH_PHHuHH-HOP9HAHuHPhL%`IA$8HXIȅA$HA$HHXvHH-T9UHA$HH?vH9UHA$HH-vH9ULH"vH>HL$ LHHSffDHuHH MHhHHHA8HEE8HIE8HHjSfH0A\_^][ SWH(H=CzHzHHH3Aȅt"zHLI3IH(_[H(HHuHHH(̠SUVWATH0H HH_PH3Ht@H;tH 93HH_PHHu?HHHOP9HAHu HPhDL%GA$8HGȅt}A$HA$HH=tHH-Q9UHA$HH$tH9UHA$HHtH9ULHtH>HL$ LHHQH0A\_^][̀SWH(H nyHHSPHt=H | Ht,H{P?HOHt9QHGHKP3H(_[ SUVWATH0H HH_PH3Ht/H;tH 9)3HgH_PHHu/HHKHOP9HAHu HPhDL%yEA$8HqEȅt}A$HA$HHrHH-;P9UHA$HHrH9UHA$HHJrH9ULH?rH>HL$ LHHOH0A\_^][SWH(mH=zHzHLHH3Z>ȅt"zHNLIIH(_[̐SUVWH(=8H@8HAHrHHqHH?HH OH>F=H-zHMzHMiHH3w=ȅt#zHMjLIIzH DH9HHV;HjNHtHHAA?H nHHHnpHHHH觞HH NH(_^][@H(7HH]pHHH( SUVWATH H HLeXI$3H=tMH pH0H v誜HHHHH 2/HLHHVHIHEXH A\_^][̐H(H +H@PH(pH(H HHP3HH(PSWH(H HHSPHt=H xYHt,H{P?HOHt9cLHGHKP3H(_[HHSUVWH8HHHGH?H6H eHtH9t Hӿ8Hp;CsHcH Hc HHfHH8_^][H@H-IHHFHHH2HHO9HH HtH9t H1HtuHO9NKHȀ;DCLKHC HD$ HGSHLIH8_^][H%SHxL HIH8_^][HH8_^][ç $pA4A5`PSUVWATH H8HH-L%WI $HLHH躙?HH?H-I $ýHLHH芙HH?H A\_^][SUVWATH H8HH-L%tVI $cHLHH*?HH:H-DI $3HLHHHH7H A\_^][PSWH(HHH HHHHOH贼LHIH(_[HH(_[SWH(IHHCHt-H 4HtH9t H袼f?HW8H>6LIIuHC4C5H(_[̐SVWH IHHHKHt09EH oHt H9tH8uNLHHC7t8HCHt/H aHt H9tHϻ8HdȅtC7H _^[SUVWATAUH(IHLH{LiI L%j9A$L-',HIM{fu HHH(A]A\_^][H"f;CHKH-iHEH2HOHHnD9H5tHtH90t HHͺHHO9HHtH93tHH裺HHEHA$HIM詺t3@;JHH J;tD@JJHH H@HP`uHOHt9HFH(H(A]A\_^][PSUH8Hl$ LE@HU8HM0HeHIHta9CCLH MtI9 t I觹LMt4H@hHA;AEHUH |*蟹HHELE@HU8H]0HHRH alHp3He][Ð̐SUVWATH IHHHKHtzL%mB9A$H-rHtH9(t HHʸHtKHK9A$HtH9(t HH襸8uHLHHH A\_^][HH A\_^][SVWH HHN9AHH }HtH9 t H-HHtgHfH 6HH (&t3;@JJHH HL@`@HIH _^[HH _^[PSWH(IHHHO9AH |Ht H9tHuHt8Hȅtd3H;C sHcH OHc HH1HHHH(_[HHHHH(_[HH(_[f̐SVWH AًHHN9D@H |Ht H9tH諶Ht8H ȅ3H sHcH Hc HHB8HBB8HBfjB8HvBvVB8HjBbHH _^[HMHH _^[H7HH _^[H"HH _^[HNHH _^[7K_w0IL8H @;~A@7 SUVWATAUH(LIIEHHcH3HH %-(I}HL0H訵HH 8豴HLHHxH=iH 荴HLIHTH n舴LDLHIH=uH IHLIHHIMH=H HLIHHIRIM9I@I}HbHH $跳HhHH?HHM@IM9H@IxA$JI$I A$Ju H_bH HKbHH9H(A]A\_^][HH(A]A\_^][@SVWH RH mxHHpHHu&H iHHHHԲ@HpH _^[Q7A7Q6̰A6̠SH HHtl:BsHcH ^Hc HHCJHz1JHJ~LGHIH [HH [(GH(Mt!A8A@uHIHt 9~2H(SUVWATAUH(HL%:hLIH HH 6K)HLHHHO3H=L-!IMHLHH迌H?LIH赱HIMHLHH舌H'3)+HLIHtHH J}HLHHD>HH2H5.HL%JH {J>HMHH?HH2HH M HMHHԋ?HHHLHH JHtHH9tHH ɬHfDH J蜬HHH]9g2LII;HHA9Hq>HLȅfHUH ^HtHzq8HL1LIIH2HMPHI9 8He(_^][̀SH HHKHt09V5H qHt H9tH轫8uHHHKHtHPpC4uC5tS4DC5HHC4C5H [A5SUVWATAUH(HL%aLIHHH DɪHLHH萆H'(H=L-IIM蘪HLHH_HL@IHUHIMaHLHH(Hg&$HLOIHHH "DHLHH>HHm'H5'HL%H DީHMHH襅?HH'HH G譩HMHHt?HH6H}(H5IMyHLHH@?HHa4H=BIMIHLHHH&H=IMHLHHH&H GHH5Hu HHΨH>L%H FȨHMHH菄?HH5H>H5NH F蒨HLHHY?HH5H(A]A\_^][@SWH(HHOH91HH mHtH9 t HEHfHt{;t HDJHH JuCHO9v*ȅtHO94f-LIIHH(_[̀pSWH(HIHtJ90HH lHtH9 t HYHHt;H@;t@H(_[SUWH0Hl$ HHeHOH9w0HH 5lHtH9 t HۦHH]Ht;JHH JtZuOHO93ȅt;u%G,LIIHH]f3;He_][@SH H LIIuHKHt9 2HCH [SUVWATH AHHKHttL%L/9A$H-kHtH9(t HH詥HtEHK9A$HtH9(t HH脥8L 2D@HIH A\_^][HH A\_^][`SH HHKHtHPhHCHHCH [0SH HA8A@tlIHHSHH;u3HuHuWu4H[Ht+;H#;HE3AHH [HH [̰SH HHKHt9V0HCH [̐SWH(HA8A@< unHOHte9-HH ViHtH9 t HHHt8;JHH Juu HO90H(_[H(HI9/H~0H(SUVWATAUAVH LIGA\$0H t.HH)Il$HHHM90HM930HM93 0HM90H]0;HH/H}H5&L57I臢HLIHN~?HH/HuL-LYLe|II2HH ;HLIH~>HH/HuL{IIHIHLIH}>HHJ/HuL{II謢HL-?IM象HLIHx}>HH /H}H5IM}HLIHD}?HH.H}H5:H c?FHLIH }?HH.H}H5IHLIH|?HH.H]H >HHH-I\$HH贠H&LII;HH-H A^A]A\_^][0Q5 A5H(HIHt9,3HxH(Q4A4HASWH(HI9Z)HH eHtH9 t H辟HHtI;@HJHH JtL%LIIHH(_[PSVWH HH <0HH *HO(HG0w0HHH _^[HH _^[SVWHHHL$ HA IQ|H@Džt3DHD$(H3Ʌu3HD$ HH@HFHĠ_^[̀SWH(HHO(9(HGHtAA3HH_;H;AAHHO93H(_[ SVWHHH|$ HA IHQ{HHD$(HLHGHCIHĠ_^[H(HIHt9)HH(̰SUVWH(HHM9&HH bHtH9t HHHJHEH8H5#HE3HuHȅt*H}@H ~艕HHH;HO8HGHeA\_^][PSWH(HG@HH }2HHHHOHLaHIH(_[HH(_[A6SVWH 2H HHHHu&H GL袔HHHHd@HH _^[̐Q6̐SH HHC88@sHcH Hc HHC7 fC4C5H C7uC@t8HCHt/H p|Ht H9tHS@8H`C7C@HC88@H [ SUVWH8HHHWH~Hu;CsHcH jHc HHIHH8_^][H23H-HH HtHHHfHO9H TXHt H9tHHHGH V{Ht H9tHԒ8HXHO9HȀ>DFLNHF HD$ HyH {HtH9 t 膒H:HJSLIH8_^][HCH zHtH9 t DHА:HJSLjHIH8_^][HH8_^][ 0SUVWATAUAVAWHXLIIGHHHD$@HߑH8AOHLk@I zHH 8蓑D0IH4LH HH KLLHIlHH _ LLIIlHH C!ΐHLIHlHH 誐HLIHqlH-:H [#膐HLIHMlH z聐HDt$0H\$(H|$ LMIHnH= H 3HLIHkHH7}IO9HIH?HHL$@H ϏHhHH?HHeIO9`LIIHXA_A^A]A\_^][HHXA_A^A]A\_^][SUH8Hl$ LE@HU8HM0HeHIHta9LH TMtI9 t IgLMt4H8>HA;AEHUH <_HHcLE@HU8H]0H3}HC8HC@H H83蘎He][ SUVWATH0H:ȅ/L%A$8Hȅ|A$HA$HHP=HH-^9UHA$HH7=H9UHA$HH%=H9ULH=H>HL$ LHH@DžHC6<C70HT8H H3H|ȅt-HHL$ LHH3,L% A$8H ȅt}A$HA$HHQ;HH-_9UHA$HH8;H9UHA$HH&;H9ULH3;H>HL$ LHH H0A\_^][PSHPD$8HD$HHD$@D$0D$4HD$0HD$ LL$4LD$8HT$@HL$H-3ÅtTD$8sHcH Hc HH&H}:HHy:H@Hq:HHQD$8sHcH PHc HH#H :HH6:H H1:HHHP[ 0SUVWATAUH8HH)L- AU8H ȅHHHtvAUHAUHH@9HL%N9A$HAUHH&9H9A$HAUHH9H9A$>Hl$ LLHHH8A]A\_^][`SUVWATH0HCH3ɅKHKH,HK9H sHt H9tH膉SH8HL% A$8Hy ȅ CHA$HA$HH%8HH-39UHA$HH 8H9UHA$HH7H9ULH78H>HL$ LHH}A$HA$HH7HH-9UHA$HH7H9UHA$HHx7H9ULH7H>HL$ LHH[H0A\_^][гH(HI9H 8rHt H9tH8H|HHH(HH(̐SH HHK9KH qHtH9t H貇f8ƀhHC6C7HC8HC@H [0SUVWATH0L%jA$8Hbȅt}A$HA$HH6HH-,9UHA$HH6H9UHA$HH5H9ULH@6H>HL$ LHHH0A\_^][̀SH HHK9H KHtH9t H肆f8AH(HK9H [0SVWH H ]hHH8HHu&H >HHHHą@H8H _^[бLMtNA8A@ sHcH :Hc HH"HmIIHHkIIHpSUVWH(HHM9HH JHtH9t HHL$ LHHy fC73ɅK7K7L-VAU8HNȅ+C7AUHAUHH/HL% 9A$HAUHH/H9A$HAUHH/H9A$LH/H>HL$ LHH AUHAUHHu/HL% 9A$HAUHH[/H9A$HAUHHH/H9A$LH/H>HL$ LHH* H蝾H=^L%8HA$HHK9c HH iHtH9 t HH؀;H8HA$8H 8HF LIIHH}H+ 83H_HH LwHHEHE3E3HUHLHL%HtIH9tHIHf9 LMHd.HI[HHLD$(HD$ AHL5A8HȅAHAHH-HL- 9AUHAHHf-H9AUHAHHT-H9AULH-H>HL$ LHH6 I HMHtHIC9LHe A^A]A\_^][SUVWATAUH8HH(:BsHcH #Hc HH8HOHHK9HH }gHtH9t HK}HHK8?HeX3VHC8HIC63ɅK6K6 L%A$8HȅJC6A$HA$HH+HH-9UHA$HH+H9UHA$HH~+H9ULH+H>HL$ LHHaA$HA$HH'+HH-59UHA$HH+H9UHA$HH*H9ULH+H>HL$ LHH:HC@HHK8r{T C7C6HH6+H6XHH{LD$(HD$ AH8L%qA$8HiȅA$HA$HH!*HH-/9UHA$HH*H9UHA$HH)H9ULH*H>HL$ LHH4HL8HHHK9H dHtH9t Hz8HH)HH WHHzLD$(HD$ AHL-GAU8H?ȅAUHAUHH(HL%9A$HAUHH(H9A$HAUHH(H9A$LHN)H>HL$ LHHH[H8A]A\_^][Ð̠H(HI9H(̐SWH(HHҶH myHHHHOHxH(_[PSH HHKHt9HCH [00HH SH u虹8H޾Bf uAָ*2ہu LIIHH [̰SVWH IHHLHHtIH9tHIwHH9HLHtIH9tHIwHHtQ9HH HtHH9t H kwHHhH;tKtA3HٷHqLHHH _^[HH _^[УSUVWATH0HHD$$D$ ȅHHdHD$$D$ LL$ LD$$HH菸ȅH HtHH9tHH vHfHH]|$$u0HxHAHMHI9~HH|$$?HHH }HtH9 t H vH؀;>H uuH@H4HH uL3IȅH=A<$IH~I8HȅbCDuA3HI>ȅtuH%HH ittHhHHHH!HQHn8H8H8HHH$HüHHH HtHH9tHH tHH vtHHHJƅH=$H HtHLHHPH CtHHH4\$ HoLDIHƅ fƅH0A\_^][`tРРSUVWATAUAVAWHHLLA<$IHu'H sHHHIHH\$ IHHT$(8H8H'LIIIHH#HAE3HH#HH BrrLIhHHHL=Hv HD$0HrHMIHNLHH誺H "HIhHHL=HL$0H irHMIH0NLHHZH S"HIhHHL=HL$0H rHMIHMLHH H "HIhHHL=HL$0H qHMIHMLHH躹IHD$ HH!HIhHHL=HL$0H lqHMIH3MALHH*IHt$ 8HHD$(HH  H c/dHHHH xdtHHHM >ȅrfHHM >H]pH dcHxHc@H bcHhHcHHʤHe@A\_^][0H(ϤHt8HHHH(HH(SH 2t(ȅtH [БSUVWATAUAVH@H3HL$0HL$83LMeEHcI;IT:HL$ HL$ HHD$0HAHD$8L5HL$0A;~ HL$0AL5HL$0A;} HL$0A萃A;|H@A^A]A\_^][obSH HǃLǃƃǃƃHHSLԢHIH [HH [̠SUWH0Hl$ HHH}0HeEHUHaH`Ht HHPxHH ޯHtH9 t HDaHؐH`H`HUHmaHe_][ SUVWH8Hl$ HHH]@HeEHUHaH`HH;L%]H V_HMHHh;?HHyH6L?KIHT`HH z]_HLHH$;>HHƅH(A]A\_^][̐SUVWATAUAVH IHBsHcH Hc HHH 9^HH8H (^HP#HL%ȠH ^HMHH[:HHH HtHH9tHH ^H>H8HH8+fDL-YLHtIEH9tHIM<^LL5z#LDIH^HH ^]HLHH9A<$HIOLHtIEH9tHIM]LLDIHu^HL5I{]HLHHB9A<$HIHtIEH9tHIMo]HH=I-]HLHH8>HHH 1HtHH9tHH ]HfDHQ"LBH]HH 8\HLHH8>HH;fDH HtHH9tHH \HH!LPBH@]HH I\HLHH8>HH@H HtHH9tHH 1\HHo!LAH\HH [HLHH7>HHa@H [HH0H %o[HHL%HH d[HMHH+7HHH HtHH9tHH X[H>H8HH5H A^A]A\_^][ Z:PSVWH HP9fHL4HtIH9tHIZHȐHH HH HtHH9tHH ZHHÅtYH HH KZHAHH5H +ZHHH>HHeWH HH YHAHHV5H oYHHHk>HH H _^[SUVWHHl$0HHeH VYHH3.HxHcHAH;HL9zH;tfL;|ȋLA;t;uH胚HxHcHAH;sH\;3HE0HE8HE@HEHfWD$ fWfWHM0;HM0HHEHAHEHAHE HAHE(HUHXHeX_^][ЇSUVWATAUAVH)$)$IH3H$H$H$H$3HD$`HD$hHD$pHD$xH MWHH)L-;HAUL5HIWHL%NuƇ HD*u%Ƈ8HZ\H($($HA^A]A\_^][SWH(H=vȃ2۹wȃ~H(_[SUVWATH HHHAHLHZLH7}HHHHL%ZHA$HH-HtHEH9t HMUHЀ>H+LLIHA$HHtHEH9t HM`UHH@HLH׶LH|Ht8HH A\_^][̰SUVWH(HHHt;HfHLH/LH |HHHyHH-/HUHH HtHH9t H rTHЀ>HL<IHUHH HtHH9t H 4THАHHLHLHc{Ht83HH(_^][̠SWH(AHًL;}jHxLcHAL;s`JLHtM9՚8HQ8HKHH HtHH9t H lSHH詓H(_[SSUVWH(HHxHcHCH;H\;3H (RRHHCHH S5HxHAH;sNHL98H=HH`~D@HHH(_^][HH(_^][RPSUVWH(HHxHcHCH;H\;3H XQQHHsHH 4RHxHAH;sWHL9%8HqHH`;uDCHՓHH(_^][HH(_^][Q̐SUVWATAUH(IHHHȅ?G<ttttfDƆH zRHQH}tG<u$SHE3HH(A]A\_^][HiXHxCHcHAH;NH\;3H O]PHHHH PDtHHH(A]A\_^][Hu HHH(A]A\_^][Hu"H+HH(A]A\_^][Hf3H OOHHL-5HAUL%HI $ODHtHHAUHI $ODHHH(A]A\_^][HH(A]A\_^][fO`SUVWATAUAVAWH8HH P)OHHƖLtH HL-HAUHL%HHtI$H9t I $NHL5HAH-jH KNHLHHe*HHH NHHjHHHAUHHtI$H9t I $oNHHALWIHAUHHtI$H9t I $;NHHL(IHAUHH HtHH9t H MHHH-HUHHHHHD$ L=IMHHHD$ HHHHD$(HLIHAUHHtI$H9t I $iMHHAHUHHHI+MHHHD$ HGHHHD$(L;IHAUHHtI$H9t I $LHHAHUHHHHH8A_A^A]A\_^][|SWH(IIHu3M:HwLH XMtI9 t ILLA;AC@ACD| |2H(_[p|SWH(HHH HHHtHt96HHHH(_[0|SHpHO3HD$PHD$XHD$`HD$hfWD$ fWwHL$P;HL$PHHD$0HAHD$8HAHD$@HAHD$HHT$0HHp[̠{SUVWATH HHtHHHH vHtHH9t H !KHHHJH}L%H }JHMHH&?HHHHt"HEHt9HHUHH A\_^][zSVWHH|$ HA IH'HHcHD$(LHGHCAHĠ_^[̐zSUVWH8Hl$ HHH]@HeEHUH=JHXHH[%H lHt H9tHIHHIHUH JHe_^][ zzSUVWH(IHH JNIHH;k |R>H腐8H8HHH AHtHH9t H IHAH.[|\>H,8H8HHH HtHH9t H HHHHH(_^][HH(_^][ ySUVWATHpHƆH@HHHM9LHH HHHGHljH߉H@HIH9LH GIHGHHHGH}L%jH KGHMHHe#?HHHxLE3GHxHAHHI93H݈HxHAHHA8H]3HD$PHD$XHD$`HD$hfWD$ fWfWHL$P?;HL$PHHD$0HAHD$8HAHD$@HAHD$HHT$0HHpA\_^][GPwSUVWATAUH)$)$D)$D)L$pD)T$`H3HL$PHL$X3HD$@HD$H!H苇Lt,2HxHcHAH;bHD8tfEWAJEHDÅt3HHxFLcHBL;JL9t7u,ÌH3Ht H ҤjHt 8D`ƇHxFHcHAH;{HD8H4HxFHcHAH;FH\;3H DDLI$L-3HAUHյHH DD*DXXDYDXHxHAH;HL9I$AUHH D*Y=8AXA\HEHHL$0LHL$0HHD$PHAHD$XHD$P0*\HEHHL$ LHL$ HHD$@HAHD$HHD$@8^=XX=HDHxHcHAH;HL9Ċ8HHH`*HAXYЃ*Y0X^(X\+*f.r\fWf.rfW($($D($D(L$pD(T$`HĸA]A\_^][@#CpsSWH)t$p)|$`H3HL$PHL$X3HD$@HD$HTHHHHL$0LHL$0HHD$PHAHD$XHD$P0*\HHHL$ LHL$ HHD$@HAHD$HHD$@8^=XX=HH}9^5XH9^\+*f.r*H9\*f.r(t$p(|$`HĈ_[ rSVWH I:HbHH8H?HqHLHj?HLHH U@HHt(;HHHȅt HDH!HLHu3H _^[pqSH0HD$$D$ D$$D$ HhLL$ LD$$HBȅtHtLHHgHu3H0[qSUVWATAUAVAWHHAD$0DHD$,D$(D$,D$(HhLL$(LD$,H輁ȅ|$,HxHcT$,HAH;HL9ІHH[}HHH`DE/3EH8HHH XHtHH9tHH 0?HH;HH qKH>LMD$0;|VEtQHHEA>>H =>HD$$HT$$H >LHIRAHH豀A>>H =4>HD$ HT$ H >LHI}A;DKHHA_A^A]A\_^][z>oSUVWATAUH(Hl$0)ED@8HH0He3HHHHEPHEXAąH~HH~3HHHHfWD$ fWfWHt;HHHEpHAHExHAHHAHHUpH@3 8PAUHxFHcHCH;H\;3H ;e>H m89HHHH ^I9tCHHw{HhHt,9A$HH8Ht8@@u HH'yH A\_^][iƁiSVWH0HHD$$D$ @2tOȅt@@ƅD$$D$ H HtHH9tHH =8HHHzHH yHhLL$ LD$$HyȅtFHXHt:H IF7HDL$ DD$$HHXLHHHPH0_^[hSVWH0HHD$$D$ @2tOȅt@@ƅD$$D$ H HtHH9tHH =7HHHyHH xHhLL$ LD$$HxȅtDHXHt8H IE6HDL$ DD$$3HHXLHHHPH0_^[gSVWH0HHD$$D$ @2tOȅt@@DžtmD$$D$ H YHtHH9tHH A6HHHwHhLL$ LD$$HwȅtDD$ T$$HfH0_^[@gSUVWH(AHHXHtDH %D5HDDźHHXHALHHIH(_^][HfH(_^][fSUWH0Hl$ HeHEHu3H5:HH=HH5Hu HE8HHH4Hu HE8HHH 4Hu HEp8HLHtIH9tHI4HfHu HE39HH HtHH9t H z4HHUHEHe_][eSUWH0Hl$ HeHEHu3H:HH=HH3Hu HE8HHH3Hu HEi8HH=HH3Hu HE@8HHH o3Hu HE8HHHM3HEHEHe_][dSUH8Hl$ HU8HH]0HeH:HL$HtIH9tHI3HȐHtV9HH HtHH9t H 2HfHhH;tfHM0ƁHE3HU8 He][ dSUVWATAUHHIHLD$4D$0AƅH T(Ht H9tHJ2HIsL$4L$0LL$0LD$4HIsȅt`IXHtT;Dd$0l$4HsH[H @1HH\$(Ht$ EDźHIXLIHHPHHA]A\_^][@cSVWH HH 'b1HtoH=^8HH5HH<1HtI8HHH$1Ht18HHH 51LrHHIH _^[HH _^[̰b…t**YXXX(*Y߳X߳XdzX`bSWHH)t$0HHٲH3Hw\Y5HHL$ _HL$ HHHAHCH(t$0HH_[aSUVWATAUHxHl$ EEHHe3HE HE(HE0HEHE3:HHH 4<HtH9 t H/HH;>H .Z/HHHH /HpHE8HAUEHHPHE@8HHM HMHHE HAHE(HAHE0(HHM H3H;HgwHHHM ȅuHHM H}8?Hu8HU@HHHeXA]A\_^][p`HL IH``SWHHH3H$H$MA8IQ8LHHL$pEHL$pHH$HAH$H$HHD$PHAHD$XLD$PHHL$`HL$`HH$HAH$tfHHD$ HHD$(HL$ HHD$0HAHD$8H$HHD$@HAHD$HHT$0HL$@ȅ@ƃH$HHHAHHmȅH HtHH9tHH ,HHtu?HLHtIH9tHI,HHtD9HH HtHH9t H ,HHhH;tHlȅtHmHĘ_[P^SUVWATH@HHDŽ$4DŽ$03H$ H$(3H$H$$4$0L$0L$4HHmȅu3L~H j#h~tHeDtHrem>H v!#h~@}#M@HHL$@ HL$@HHD$PHAHD$XL3@ƃt;t3HHfDHxHcHAH;HL9HT$PHHD$0HBHD$8LD$0iHcHxHAH;sMHL9HT$PHHD$ HBHD$(LD$ iNL;3Hh_^][I"TSUVWH(IHHH9h8HHH9h;LHHHHEHHHB 8"H(_^][̐SSVWH0ILHHhIBLHIHuHD$ E3+I!LLHHgHH0_^[@SSVWH0IHHD$ HtYMtTH IEHHt=;HHt,8LHHHHFHHHB N! 3HD$ HD$ H0_^[RSUWH0Hl$ HeHEHQHtHH9t H < HHH= :HHLWHtIH9tHIHH9LMtHI9tIH LMt_A;ILHtIH9tHIHHt-9HH HtHH9t H sHHUHEHe_][̰QSWH(HHt\H=;HHtHH83HۭHL!HtIH9tHIHHt 9pfWfH(_[@QSWH(HHH,_ȅH HzHHHPHHtl8tHxHcHAH;HL9eHHHHHtH };CHHHHLHS_HHHHLH+_HHH(_[0PSWH)$)$IH3HD$pHD$xHHt;HHt/HHt#HHtHHt unLH]HHHHHHHHHH@HHa]^5L?HHL$`HL$`HHD$pHAHD$xHD$p8f.v{H8`f. zu Hb]$YoHHL$09HL$0HHD$ HAHD$(LD$ fWH"]H9u\f.wH\fDH9`H=f.wH\|DH9H9`\Y=ҞHHL$P`HL$PHHD$@HAHD$HLD$@HI\HQ\($($HĨ_[̐MSH0HD$$D$ ƃD$$D$ HhLL$ LD$$H\ȅtDD$ T$$H[H0[0MSUVWATHHl$0AډHHHe3HHHHHHxDcMcHBL;JLH9?aHHDAHHPHH8HH`HHHHAHHAH+HH0H3H;HaHHHȅuHHHHxpHcHAH;HL9F`8HH HiZHxHAH;H\;3HEpHExHHfWD$ fWfWHMp͢;HMpHHEPHAHEXHAHE`HAHEhHUPHHDHhDDHcXHH LLHxLLHxLHcHAH;HL9n_H9HHL3LH$YHxLHcHAH;HD83HE0HE8HE@HEHfWD$ fWfWHM0;HM0HHEHAHEHAHE HAHE(HUHWHA\_^][a̰ISWH(HLxBHcI@H;sKILHt89]Ht+HxHAH;s$HL9]83HH(_[@ISH HHWHxWHǃHǃHǃǃHǃHǃH [HSUVWATH@)t$0HH;3H HHHL%bHI $0HH9E3H?Ht$ HT$ I $LHHƅHV(t$0H@A\_^][HSVWH`)t$PIHHDH\HUH oHH63HD$@HD$HHL$@ HL$@HHD$0HAHD$8HT$0HHHD$ HCHD$(HT$ HH3H H;LHƆ@(t$PH`_^[GSH0)t$ HHHHHt}HHtq:`f.Hv 93 9H9`f.vH93fH9R(t$ H0[`FSWH(HHHt+HHtH=9H9H(_[ FSUWH0Hl$ HHH}0HeEHUHHXHt HHPxHH F`HtH9 t HHؐHXHaHUHHe_][̠ESUVWATAUAVAWHhHl$ He3HEHE HEHHHLMwA<$>H JH@IeHH H3HЌȅ);HIH؀;HLIILLm(H+MME3HIMAHE0HH a8HHHu8B>HHMHMHHEHAHE LuA>IVIEE3IMHH HtHH9tHH HM6A<$>H LI0I-HH HtHH9tHH HA>Hu#HHHHE3LIPpuRA<$IIHH }tHHLhH3HLhHHLȅHM8HtH`9LHM0HtHN9LHM(HtH<9LfHeHA_A^A]A\_^][BSUVWH(AHH3HdȅuwH5^;HHtcH8HHȅuK3H֞H>HϞ~+DLËHkRLDRHHIH(_^][H6;HbH*RL3RDLËHIH(_^][HfH(_^][BSUVWATAUAVAWHEMDLE3ۉ\$(H5 >H6HH|$0H!HD$8@H <HDAH WHQHD$@H5HH ] HLLD$@3HHH脯H3t$$H HD$HHT$$HLHHH@MHHt$ HT$ HL$HH LHHH)H\$PHHD$XHX HHH HD$`HLI;H}HD$hH! HAHHHΜHD$pHHHœHD$xHHT$0HLHHL$XH HHHD$PHHD$`L I;HL$hH HAHHHHHD$pHHD$xH|$0H LHHHHL$8HhHHHLHhHHHL$8HhHHPLH6A}HI\$(\$(A;fHĈA_A^A]A\_^][?SUWHPHl$ HHe3Hȅt 3@E;H-LIIHH}H}HҚLE3HHLAHE HH Ʃ LIIXEHM HtH9LL]IIHMHtH`9LEHe0_][ >SUVWATAUAVHHl$ HHHe3HEHHEPHEXHE0HE89HHM0HM0HHEHHAHEPHAHEXHHMHLLe`HHA<$H=L >H HEhH0L-=LIAUHu. Hغ>H H0LIAU>HHq H )H I H`HAHEHAHELHMHHE HAHE(LE HH7=HA<$>H [LIH=ULIIL5_IALHMtHI9tIH LM{HuKILIKILI>HSuKHHH $HhHHA<$ILIq%HȅtLHHH 6HhHHA<$ILIHQHH }HHhHHHHHHHHhHLHHA<$ILIIE3II}IIAHHtHH9tHH %Hf9DH>HŖu;H}`3ɀ?HEhH8E HU H xLHH>H}`?HEhH8EHUH wLHHDHHLȅtH HHMHȅHepA^A]A\_^][̠9SH HH3HL;IHHIH [HH [p9SWHHHH )H xH`HAHD$ HAHD$(LHL$ HHD$0HAHD$8LD$0HH`9HH_[8SVWH H Р3HHߔHޔHHH8sHcH Hc HH&$@HH8@HH8fDH uHE3HH#HHgHHXHHH _^[ 8SVWH@H3HD$ HD$(Hu39HHL$ H ߡHT$ UHffHHLȅu 3HHLH؀;>H H0HHLptHtIH9tHIHHȅrH#HLH@_^[ 7SUVWATAUAVAWHhHl$0IAHHeE3LULULMLHEE ;HHMH HU)H3H?HLD;~H}?HLHL5 HtL93tHIH؀;L=>IIH@HъHH JL3I<}ȅHH0HHLHHtL93tHI(H؀;>IH0HUHH rHtHH9tH HHѭLMHHHLHD$(D$ E3IuDE He8A_A^A]A\_^][@5SUVWATAUAVH@IHH3HD$ HD$(?#HHS(AHN@ u*H CHBLHD2HS(AH @ =~*H HBLH>D2z H qHH HDO E3HHt*H ,H BLHC2}HHL$ H HT$ _LH<E3>H 5LfffffHILHILH ; Ht H9tH8I0HHL\pHtIH9tHIHȐAH}u'H (HBLHB2AH^D;EH@A^A]A\_^][2SH0my8H|H3Hyȅt%HH;HD$ AE3HH0[̠2SUVWATAUAVAWHXHl$ He3HEHE9HHMH -HUH3DH1>HL;~H >HLHH HtH9 t H)H؀;>H 7H@HRHH H3HxȅHˍ?HLIIuHLIIwHL%v{?HA$HHA$8HX{ȅ;H){HHxȅtHH2fHȅtcHɮHH *HhHHHHHH؀?Hz8HHڈTH>HLHL% HtL9#tHIH؀;L5>I*H0L=HALL-mMtIEI9tIIM:LM?H*HE &`yHHHLHHtL9#tHIH;>IH0HAHHtIEH9t IMHЀ?HM>HM HtHh9LHMNHMC;H*yHHvȅt$?H+LIIH;He8A_A^A]A\_^][SUVWATAUAVAWH8Hi Hl$ Hm HM HtH9LH8A_A^A]A\_^][SUVWATAUAVAWH8Hi Hl$ Hm H%H8A_A^A]A\_^][SUVWATAUAVAWH8Hi Hl$ Hm 3tH8A_A^A]A\_^][0.SH0t8HxH3Htȅt-HūHHëLHD$(D$ E3HIHfffffHHL;|E3|HغH H`;E3H|8Ht=u7=uA3HHAąu;HƆ;HȅL-CtHAUHtHAU8H,tȅuQD{LIIH8H HH2LHD$(D$ E3H8PH+qHH'9{HغH ؿkHh;E3H`{8Hԅ>H;HeA]A\_^][̠)SH07H3H pȅt-HHH`LHD$(D$ E3H7H0[P)SH0H3Hoȅt-HHHLHD$(D$ E3H7H0[)SVWH0HH=;HH58H@ tH8HHHoHG H eAHHHHHHHAȅuBHHHH ȅu!HHHϥHȅtyLIIH363Hxnȅt-HzHHLHD$(D$ E3H<6H0_^['SWH(HH dCHHHHHLHHH؀?8HHHHLHЃtC | HHl$ LLHHv}H8A]A\_^][%SUVWATAUH8HL-JrAU8HBrȅt}E ~vAUHAUHHHL%}9A$HAUHHmH9A$HAUHHH9A$>Hl$ LLHH|H8A]A\_^][@%H('3H3HHH(HH( %SH0vLIIH2j8HnH3Hjȅt-H0HH6LHD$(D$ E3H2H0[̠$SUHHHl$ HeHE jLIIHH]KH;HLHLHtIH9tHIgH@2fffHI;HLȅuHUH _5HtH)8HLHe(][#SUWH@Hl$0ALE@HHeEHHHȚLHЀ;EXD$ DMPDHoHM@A ~1EHe_][p#SUVWH(IHHH p_KHHHyHHwLHLmIHkLHLaILHsLHHsHt8HHsHb0H(_^]["HA"SUVWATH HHH |HHXxHu(HH9HM H-H>L% 1H ]'HMHH?HHxHpZ;HHwH A\_^][ "H(HQ :B7uB7A0HI(90wH(!SVWH@H3HD$ HD$(HS:HL$ )H :HT$ HHHLȅtkHHLH5AHH&Ht/HjHLHtH90t HH%8HZ5HCHLȅuHK9H@_^[ !SH HHCHKHt9HCHtHw/HH [HH [ SUVWATAUAVAWHHl$0EDHHHeHE HE(HE0E83HEHEH 7HHHu@ueLEFE3IILLeHfDH)A<$ILHH HtHH9tHH HL=f;HAHHHȅu.HAHt#AEADL$ ELHH4.@HA<$ILȅQHUHH Z>HtHj8HLHHCHtH-HKHu@HHC 8@4HC 8H4AIIA;3E3HW:HM&H 7HUHE3Hǯ;HLAE;~H;HLL-2HIHtHHLHILMuH ZHHqHqHGHt8HGL;u/HG8@Pu HO9ȅu HGHE HO(9sHO(9sHOIRH_;>H 2H@HpHH p3HHG 8H6EH+HG 3ɀ8H6HHHHu@HHHE HeXA_A^A]A\_^][PSH HHKHtO9'sHcH <Hc HHHC 8@7HC 8@4@5H [SUVWATH`Hl$ HH}pHe3HE HE(HE0HEHEH_Ht HGHu3|;>H 8H@HSoHH HHu83Hdȅu,Hd>HHtH8Hdȅu2G0tLHO9APt輐ȅu HO9/H_3HuHH)G0H#tȅtHO9/HG 8H6HW:HMHMHHE HAHE(HAHE0HHM HH5HHHt^HHLHGL;tGA;ICHHt8@3Ʌ3u A;ACPtA;I.fHHHM ȅ^fHHM HupHNHtv9APtQE3AE3Aąt HN9I.H~HNH]893HjtHH'Aąu HN9 .HF 3ɀ8H6He@A\_^][SVWH HHGHu3HHOHJ'HHGH;uHGHO9"fH5!HHHt$HHtH93t HH8HE-HO9HnH _^[pSH HY;>H {H@HlLH |MtHI9tIH LIH [ SUVWATAUAVAWHHl$ ALHHHeH 1,LDDHIT,Lm0?Hl^HHA}H5%>HHE8H0LIgH?p8H3sHHxH )H PH`HAHEHAHEfLHMHHE HAHE(LE HH>Hغ>HHLIcf3%Hغ>HLI$LI0fHqHHHHhHHHHHH?HHhHLHH访I$LIeA}>H ,HHH5iILH=tzMtHI9tIHLm8IE H= RHU HLHId3I8EHUHLHIdLI@MIdHpH]@H{HEHHGHHHoHEP>HLI;L=PIHAHHwHoHEXHHHoHE`HILIdHMHH HHHE@>HHEPLI;IHAHHHHHEXHL}`AI LIcHǑHH x HHhHHIHLIZcHHHhHIPLI-cIdoH؀;H]oHHYoHH PHH?H ۨfLp ;HH oHEHHtHHHE@;HHEPHE33HLHHnHAI(LIkbH9IѸH!HexA_A^A]A\_^][̰H(PH ǀH(̐H(^nH(̀SWH(HH4n!r!*P `YPXHYHmHR!AAHH(_[HH(_[SUVWATAUAVAWH)$)$D)$AEDL3H$H$3H$H$3H$H$3H$H$3HD$pHD$xbbHH$1mLÅ3jLI\$HcH;ITH`jH$:HL$`HL$`HH$HAH$H3jH$H$;~UID$H;IT:HL$PH$HL$PHH$HAH$H$H$;=H$*I(lAŅ A?IlLIIHL$@HL$@HH$HAH$H$xHH YHH K#ufWHHHL$0LHL$0HH$HAH$H$pHHHL$ LHL$ HHD$pHAHD$xHD$pHXAXX=^AXP\I k($($D($HA_A^A]A\_^][fSUVWATH0HLD$$D$ gȅSHItHD$$D$ LL$ LD$$HIȅH wHtHH9tHH HfHIm?HQ_HH HtH9 t H]HS8H WH3HWȅH=W}HHzH8HVȅ^;CDuA3IxHfȅt`HHH mHhHHHHH8HHlV8HHdH)HI I8fHH vHtHH9tHH 6HH u HHHdAƄ$H=mH vHLIH萳H vHHHe\$ HcLDHHeAƄ$AƄ$H0A\_^][̀ ̀ SUVWATAUAVH LHHH H1HAHH蕲H$SHH zpHHH:H}HQHH tHtHH9tHH HHH HH sLHH8L5H pjHMIH1MLHH0I$PHH%H;Ht=HƈHH gHhHH?HH0dHH8L5_H oHMIH蚱MLHHHHt=HRHH vHhHH?HHcHH8L5H oOHMIHMLHHHHt=HއHH _HhHH?HH(cHyH8L5wH nHMIH蒰MLHHHHt=HbHH nHhHH?HHbH3H A^A]A\_^][̐ SWH(…tFHPHHH fHhHH?HH/bDHPHHH HhHH?HHaH(_[ SWH(HHȅM8HjQH3H\NȅtiHHeQHH #D~uƃHHHLAH XLIIHH(_[@ SWH(HH_ȅtX:M8HPH3HMȅt1ƃHcHHaLHwAHH(_[HH(_[SWH8HJ3ɅJJH]Ju HHHH@LI;Ju3fD$ HT$ H BHH"^H8_[0SH L8HOH3HLȅt)H]HHLHaAHH [HH [SH HHpHH HHH [HH [̰̠̐SH u8H^Bf uAV*2ہu rVLIIH{H [0SVWH IHHLinHHtIH9tHINHH9HL9nHtIH9tHIHHtQ9HH nHtHH9t H HHhH;tKtA3HYHLHHH _^[HH _^[PH(HIHt9[H(@SWH(HHG8@6I8H"MH_3H^HHXHG8@6H(_[SUVWH(HH HHtujHG8@6/I8HLHDHHHG8@4t3H0^HHHOHIHG8@6HH(_^][PH(HH(@HA@A0A HHAu AfSUVWATH HH~HH-?L%>I $OHLHH?HH'^H~H-I $HLHH?HH]HN9]HFHFH A\_^][PSUVWATAUH8HH3HJȅHMHt9]HEH]HH_H E?H\HD$ HT$ H gjHH kKHAHH1]HuHHH9]H>L%L-H5 IMHLHH~?HH\H8A]A\_^][ SH HHKD؋CD;t CD[CH [HhSWHH|$ HA IH腨HHD$(K;LHGHCAHĨ_[̀SUVWATH IILHdž`ƆhH "hHHaUHXHBD$IH 3ҹb[L%xEI $H HH(HH0HT$pH8HT$xHH cHH|H.I $LHHHHH hhHtHH9t H HHPTH A\_^][@SUVWHHHHXH-H 9+HLHH?HHTHX 3HL$0D$(HD$ E3E33HL$0葩;HT$0HSEH u H\4fHVHu$H fHHVHHVHH_^][PSUVWATAUAVAWHhLI\VHu$H f;HHGVHICVHHH\$ HbHD$(HHHHzHH HHhHHL-SHLl$0HHAUH5 H>aHD$8HHLIHHHHHD$@HHL=}UIAHHH\$H8HL5HLt$P8HHAH|$(H.HHHD$ H zHHhHHHAUIA8H8HHAHHHHD$ HyHHhHHHAUL- HL$8H ~HMIHEHHHD$@HHD$H8HHAL5{D3HAHL$(H FHHHD$ H2yHHhHHHHD$0L-+ HL$8H HMIH譡HHHD$@HHD$H8HHHD$PHL$(H HHHD$ HxHHhHHHHD$0L-. HL$8H YHMIH HHHD$@HHD$H8HHLl$PAUHL$(H *HHHD$ H&xHHhHHHHD$0H5 HL$8H HLIH葠HHHD$@IA8HHD$H8HHAUHL$(H HHHD$ HwHHhHHHHD$0H5 HL$8H 7HLIHHHHD$@IA8HHD$H8HHAUHL$(H HHHD$ HwHHhHHHHD$0H5 HL$8H HLIHkHHHD$@IA8HHD$H8HHAUHL$(H qHHHD$ HvHHhHHHHD$0H5HL$8H HLIH؞HHHD$@IA8HHD$H8HHAUHD$(HHHHD$ HuHHhHHHHD$0H5sHD$8H~HLIHEHHHD$@IA8HHD$H8HHAU3HAADŽ$`HhA_A^A]A\_^][ SH0<8H@H3H?ȅu-H-uHH3LD$(HD$ AH H0[H(H3RH(̰H(HRH(̠SUVWATAUAVAWHHl$0HHHeHEXHEPE@EHEDE<E83HM HM(HM0HE`HMHMHE@HD$ LMDLEHHUPHMXNȅ H@9bJHL0_HtIH9tHIHH LH ]MtHI9$tIH L}HHsHH +1VHAHH躛H [6HHHCA<$HInJH@HPsHr;HHNE@HsHH 0ʿHAHH.H G[調HHHCCA<$HIIH@HrHq;HHM{HrHH 0JHAHH讚H Z*HHHBA<$HIbIH@HrH q;HH MH.rLL= IH1LHOH]hL-]IM諾LIHqLH=HHHH]pHqLIHLIM_LIHEhHqLHHHExHEHHVHHHHHHH/EHHMp9HL-nI lL.GLA<$HIAL nIHH 耺HAHHHH ]HHHHHEx8HHHLmI >lA}HIH}<}HHHMX葚ȅE@;H mHH*HH貹HAHHH?=HH!UHHzHHHHHCHHMp9HLlI WkLELA<$HIALlIHH HAHHnHH HHHHHEx8HHHL8lI jA}HIHuHlHHV)H HwHAHHۓHCLhA<$HIALjIHHH 萶HAHHHXH mHHHHPHEx8HHH`LiI NhA}HIHhHCDA>IIA?IIHxHAH;HDH}Dt}D@HxHAH;HL98HFH|8HLHHp=H{;HLHH HtH9t H_H?HHUXHuȅHE3HHPHx8HHM螏HMHHE HAHE(HAHE01HHM |H؀?H.;H/HaRHHM ]ȅuHERHM L@HHxHAH;sFHL98HxH\C"fHz;HLȅ聴HpH $$HtHz8HLHA_A^A]A\_^][9H8HAHIHSWH8HJ3ɅJJHLbI;Ju3D$ HT$ H W$zHH~?H8_[pSWH8H2t@ȅtÅR-8H0H3H0ȅuYJu!HOfH;D$ AE3H3HeHH̲LD$(HD$ AHHH8_[SWH(H2t$@ȅtÅtH HAHIH(_[HH(_[ÀSWH(H2t?ȅtÅtH(HAHIH(_[HH(_[@SWH(H2t?ȅtÅt4h3ɅhH0hHAHIH(_[HfH(_[SWH(…tFHPHdHH VHhHH?HH?DHPHdHH 裰HhHH?HH>H(_[@A8A@< tuH(HAHIH h H(HxHAHvHI9HH(HH(Ð蓰SH HxHCHv@H[;3H (軯HHC8HH H [.̠H(H耯H(̐SUVWATAUAVAWH(LH_HH D oHAHHӊHb+HH H3HHHx_H>H*HH /MHtHH9EtHH HH=H MͮHLIH蔊}HH?HEH HH L蘮LH^H8L5 H %HpHMIH7MLHH6I$PHH+H;HtCHaHH mHhHH?HH6HNHV蔅3D$$D$ HhLL$ LD$$H ȅ|$$H^;#赩HHW(AH@ uH]HLFH?HN9HW(Aȇ@ =~H]HLFH`H~ H ީHH<H載?DO E3HH诉tH#]HLFHE2H]HH 6ɨHHhHHL|$$u!AH\HHhHLHh9.HH HtH9t H褨HHt+H^?>H ;H0LH,H^A<$$H {HHUpLIs,AHVLFY9ȅHVI„HH HH调H!ZHLH賃-HH[HL-H-LII;HHx-=u AƄ$LFHUpI+H0A^A]A\_^][̠SVWH IHH d?HHHmYHHK[LHLaYIH_YLH܂LUYILHǂ,LHH,8H7H _^[SUVWATAUAVAWHHHHD$PHD$HD$8D$@D$<D$4D$0`<4ȅHP4Hu$H tD/HH;4HH74HD$8HD$ LL$H 7H0H-HH HtHH9t H PHHAD\$4D\$0HLL$0LD$4HȅL-3HAU83H%HAUL%o%8HA$H-68HUHa?HH 莤HHAU8HA$8HUHH aH|$0u?3Hy"?Hi"HxHcT$4HAH;HL\$09f8H$HH`;u}3H"}H!`;D$4D$4`|$4[H1HD$XHL5B$Lt$`8HAL-4Ll$h8HAUL%*>Ld$pHI $QH؀;HA83HAUHI $-L=V!83HAHA8HAUHI $8HAL%(L5HLHH~HHA$HHD$X8HHD$`8HHD$hHHL$pH HH-IءHLHH}?HHAUH-+I諡HLHHr}HHA$HHD$X8HHD$`8HHD$hHHD$pH_83HA||$4qH]/HD$xHL5!L$8HAL-l2L$8HAUL%;L$HI $H؀;HA83HAUHI $辠L=8HAHA8HAUHI $苠83HAL%L5:IbHMHH)|L-1?HHAUL%~I.HMHH{L% HHA$H=IHLHH{}HHAUH=/IϟHLHH{HHA$HHD$x8HH$8HH$HH$H zHH-I`HLHH'{?HHAUH-SI3HLHHzHHA$HHD$x8HH$8HH$HH$Hޞ8HAƆfH,8HHĨA_A^A]A\_^][H(,8HpH(SWHHHD$4D$0HX9(dEH \z8HH3HȅD$4D$0HhLL$0LD$4Hȅtz|$4us#LIIHH QH H>zHHLHD$(D$ E3H8du E33HHH_[̰SVWH IHHȅt]?HX.uLH5+H8H{ȅtH8HGH 脛LI$0L5 $HAHL-Z HtIEH9t IM蓛HHDI$H#HH 脛t9I$0HAHHtIEH9tIM5HfHLHHNLHIH A^A]A\_^][HH A^A]A\_^][pSUVWH(HHH9B$HL9HtIH9tHI蠚HH HH 7HtHH9tHH rHÅH}NHH 6HAHHuH 5HHH>HHP$HHH*NHH 覙HhHH?HH'HMHH n 虙HAHHtH 5yHHH>HH#HHH%MHH v HhHH?HH?'H(_^][SWH8Hi8HH3HȅuYLIIHH LH HeuHHLHD$(D$ E3H_H8_[0SWH(H)HHLHE3HLII;HH=uHf)H(_[H(H3E)H(SH HٺEH 蟗u1HGLHH8H1HHH [HH [pH(HE3(H(PSH  HHKHE3HLII;HH=uc(H [H(HA3*(H(H(HA'H(̰H(HE33'H(̐H(HH(̀SUVWATAUAVAWHHl$0))(HHe3HHDžƅHDžHDžHDžƅDžDž3H3HHDžƅHDžHDžHDžHDžHDžH Ts7HHoH(1H  HHoH d8H8H\"ƅ(E3D,6&8HcuHH0LHE[;HLHH 2軔HHHDžƅ3H%HH ^2HtHH9tHH NHHƅH L5%?HA;HHnAE,H gLEŋ(I?HA@ u!HHHEA<$HI?HAA<$HI@A<$I!>IH+n?H$H-H )H Z]H`HAHE8HAHE@@LHM8HHHAHLHHHII8H"IHr"H8HD.H@H蝒HHHN"HH>HLFI;L5>IfHAHHmL="HHAL- "HAUHIH@H HHH8>HHHLeFI;IHAHHNmHHAHAU>H 腑H LI HMYtH9#D,H0HfHW;HLȅH0H KHHtHW8HL(H(HHD$ LLHHd 8H8HHK9LH zMtI9 $t I}LLPA<$I$L-AUHHX;H&o3I4!HHX;Hn3HOpHH -HHHDž`ƅh3H5!HH -HtHH9tHH 諏HH`H= !;HHAUHX;HHIhtH`9 HLPHX@ƅiE3Dl;HoHHpuDHU;HLHH ,HHHDžƅ3H HH ,HtHH9tHH 蒎HHƅAFlH КSLEƋ(I?H A}HI+3II>IHhHIzHHnȅ.!xH ,؍LA &DËIAI@H?HH3D;H!*H*^x*^f.vA*;H*YH*^,ϋx++D*Y,+Ǚ+LLH8L$(|$ EDHHA蒌HH )H VgHH`HAHE(HAHE0L=ALHM(HHEpHAHExLEpHINA}HIfA<$I$PxD$(D$ E3E3HHHH H`HAHEHAHE ALHMHHE`HAHEhLE`HIĿHIHjHH<'HH蕋HHHFH>HL?I;L56I^HAHHfL= HHAL%HA$HIHH HHH>HHL]?I;IHAHHFfHHAHA$HI?H2HpH )H THH`HAHEHAHELHMHHEPHAHEXLEPHH6A}HINA}>H MHIhHL.#HtIH9tHIH9HMIctH95DHLPDlHp@H)P;HLȅsHpH kHHtHO8HLHLPHXiH((HA_A^A]A\_^][0SUVWATH H/=H8H udHH-~HcL%WLHHA$Hغ$H >HHNpH7LLd$@I4f.s \$H\$H|$L|$L\$HH=I@ ;}L|GIDC8E33H^HBHIIHH5H ^HI(t$PHhA_A^A]A\_^][0SH HHHHHHɀLHIH [HH [SH HH7H6ȅtH?H~H [̰SWH(HHHȅuJ?G< u HL"HIH(_[HPtuFHHH(_[H1?G<t[uHHH(_[H HHH(_[SVWH HƇHH5HHHZ3tXHHtLH qHH2HHK.HHKHHLHHHPu H$HȅtHHƇƇfH _^[ SWH(HHHKȅuHLHH@H(_[SWHhH$H3HD$ HD$(HD$8HD$HH$HHD$ HAHD$(HAHD$0HAHD$8HA HD$@HA(HD$HHA0HD$PHT$ HH$H9HIH|2HDYȅu H9HIHt2H$YȅtH%Hh_[ SUWH0Hl$ HHH}0HeEHUH}HHt HHPxHH HtH9 t H4}HؐHH|HUH]}He_][̀SUVWH8Hl$ HHH]@HeEHUH }HHH+XH dHt H9tH|HH_|HUH|He_^][SUVWH8Hl$ HHH]@HeEHUH|HHHWH Ht H9tH*|HH{HUH[|He_^][àSUVWH8Hl$ HHH]@HeEHUH |HxHH+WH 4Ht H9tH{HH_{HUH{He_^][0SWHH)t$0H3H z{Ht$ HT$ H g{LHH`(t$0HH_[жSH Hٺ3H zzHH7HH zH [̐SWHH)t$0H3H yUzHt$ HT$ H ,zLHH(t$0HH_[0t tSH Hٺ3H xoyHHHH yH [̰SUVWH8H3H xyHHHH-HHHM\yHt$ HT$ HMCyLHHHHVfDH 1tHHHHIt>I$HE@ID$HEHHU@H3HE0HE8HM0TL]0IHE ICHE(HU HL%H sHMHHOHHH)H8HH QHt H9tHsH8HHMCNHMHHEPHAHEXHAHE`6HHMP"NHغ>H r.sHX;LHHHHMPMȅuHHMPM@H(upHA]A\_^][̠SUWH`Hl$ HHe3HM HM(HM0HMHMHH8HH PHtH9t Hr8HHMMHMHHE HAHE(HAHE0FHHM LHغ>H iqqHX;E3HH膺HHHM LȅufHHM LHe@_][̠SUVWATH)$IHHHt5L%.H rqHMHH9M?HH"fH Q\qHH HHqHEH$HEH$H$H3H$H$H$H$fWD$ fWfWH$E3L$L$L$L$L$H$HHD$`HAHD$hHAHD$pHAHD$xHT$`H$AH$HHD$0HAHD$8HAHD$@HAHD$HHA HD$PHT$0HH-H oHLHHKHH0H :oH`LHC($HA\_^][̐SHpHٺ0H 9_oH`E3H3HD$PHD$XHD$`HD$hfWD$ fWfWHL$PL\$PIHD$0ICHD$8ICHD$@ICHD$HHT$0H[H[HttH9̯Hp[ЫH(ǁtǁH(̰SUVWATAUH(H-#H8H-KHMIHL%oIIL-1LHHAUHغ3H mnHHHnL"I;HMIHIxILHHAUHHmL"I;H FIHI;ILHHAUHHmH(A]A\_^][SH Hٺ3H l_mHHHH 5mH [̀SUVWATH IM9HH HtHH9tHH 5mHfHH lHLIHH>HHu}HHHHHH A\_^][SUVWATH MHHH FlHHHHMt0HUH AlHLIHHHH}H8HHHH A\_^][PHɳAH@SUVWATAUH8HL-AU8Hȅt}E ~vAUHAUHHO HL%9A$HAUHH5 H9A$HAUHH" H9A$>Hl$ LLHHfH8A]A\_^][̐SUVWATAUH(EIHLH kHHHH{Ht0HH pjHLHHFHHNAHA<$I;8HHDHH(A]A\_^][SUVWATAUHHHl$0ELE`HHHeHjH8L-4;HAUHt$HAU8Hȅu HH8H LHHHHЀ;ExD$ DMpEHfHM`A ~踱HeA]A\_^][ SUVWH8Hl$ ALEPHHeH5HH{LGHBȅtDHH;HMPA ~1He_^][̰SUVWATAUH8HL-*AU8H"ȅt}E ~vAUHAUHHHL%9A$HAUHHH9A$HAUHHH9A$>Hl$ LLHHH8A]A\_^][SUVWATH0HLHD$ HtuH1~f3H%HHt9ID$HHHB HhHtID$HHHB Hh$HIHu;|3HD$ HD$ H0A\_^][`SH Hٺ>H f_gHPHLH =MtHI9tIH ugLfIH [SWH(HH>H hffHPLH`H(_[SH Hٺ>H ,ffHXHGHH gH [̠SUVWATHP)t$@H>H eafHHXt$0H-:HT$0HMfLHHH(L%HA$LHMtHI9tIH >fLMuOHXHvHHM:fH`D$ HT$ HM#fLHHHXH'HHMe0H(HA$HHtHH9tHH eHH\H`t$(HT$(HMeLHH@(t$@HPA\_^][ H(A@AD H(ADA@SWHH)t$0H>H cedH`t$ HT$ H H hccHHLH`H(_[PSVWH0H>H 'ccH@ljD$ HT$ H  dLHHH0_^[SH Hٺ>H b_cHHHH cH [SUVWATAUAVAWH(H H8L%I $>HL5oI|>L=LHHAHغ>H 2bbHHHbL I;H ->HI">LHHAHHbLpI;L-^IM=HI=LHHAHH?bL8I;I $=HI=LHHAHHbLI;H-HMt=HIi=LHHAHHaLI;HM;=HI0=LHHAH HaLI;HM=HIH \]H`HHH h]H [SH Hٺ>H <\\HHHWLH MtHI9tIH \LfIH [̠SWH(HH>H [k\H@LHH(_[pSH Hٺ>H [/\H@HH [@SVWH0H>H W[[H8@ljD$ HT$ H G:\LHH3H0_^[SH Hٺ>H Z[H8HHH [H [̰SWH(HH>H Z;[H0LHH(_[̀SH Hٺ>H lZZH0HLH MtHI9tIH [LfIH [0SWH(HH>H ZZH(LHH(_[SH Hٺ>H Y_ZH(HLH MtHI9tIH uZLfIH [̰SWH(HH>H hYYH LH`H(_[̀SH Hٺ>H ,YYH HGLH mMtHI9tIH YLfIH [0SWH(HH>H X[YHLHH(_[SH Hٺ>H XYHHLH MtHI9tIH 5YLfIH [̰SVWH0H>H 'XXH@ljD$ HT$ H  YLHHH0_^[`SH Hٺ>H W_XHHHH XH [ SWH(HH>H xW XHLHpH(_[SH Hٺ>H H VkWHLHH(_[pSH Hٺ>H V/WHHLH }MtHI9tIH EWLfIH [ A AQDA DIASH HىSDC DKHKHT$POVHK HT$XAVH [̰HA ̠HA̐ÀAA QDA pA `HAHHu38@3Ʌ@SWH(H>H T>UHH@HHH yHTH@IHLHtIH9tHITHHM@98HHHHSHHLI$HI4HLHtIH9tHISHȀ93衖Hغ>HQSLI$LIHHH#SHHhHHHHCHHHHhHLHH01I$LI<HM@ȅu HAPHHAHHtHAH8@HeXA]A\_^][pSUVWATH0Hl$ HH]@HeHKHHt9%>H Q,RHH@H5HL%gHI $#RHt~H@HHI $RHE8HHE3H}Hȅu6H5WH QHLHU@H-?HHHeA\_^][̀HAHHu3 8@pAP`SUVWATH0Hl$ HH]@He>H jPPHH@H5HL%8HI $PHH@HHI $PHE8HOHE3HuHȅu_H=!H PHLH}@HHH,>HHH 9mPHHHHOHH+PHeA\_^][PSVWH0AHHGPEH>H COOHH@LH8;Hȅu3HD$ HT$ H OLHHHH0_^[̰̰H(.H NOHH(̐SH Hٺ.H lNwOHHNH [`SWH(腘HHH.H N'OLHHHLH MtHI9tIH NLIH(_[SUVWATH .H MNHLI$3H=tMHvH0H $`)HHHHH ѿNHLHHC.HIMHH A\_^][`SH HٺH MMHhHHH [0SVWH HH0H _(HHHHH %pMHLHH-H LMHhHMH _^[SH HٺH H#HI;HLȅuHMPHtH=9LH )HHHHHLII;HHH (GHHHHHHH8H3HE0HE8HE@HEH hHM0v;HM0HHEHAHEHAHE HAHE(HUHHeh_^][SUWH0Hl$ HHH}0HeEHUH^GHHt HHPxHH .HtH9 t HFHؐHHFHUHGHe_][̐SUWH0Hl$ HHH}0HeEHUHFHHt HHPxHH HtHH9tHH ^FHHH FHUHFHe_][SVWH HHHt$H ˶EHH!LHHNVH _^[SUVWH8Hl$ HHH]@HeEHUHEHHH H Ht H9tHzEHH/EHUHEHe_^][PSUVWH8Hl$ HHH]@HeEHUH]EHHH{ HH HtHH9t H DHАHDHUH$EHe_^][ЇSUVWHHl$ HHHeHu0HLAIH:%HHEH+%HEHEHE8HUH} LH֋%HH$HDHE0HHH@HATH}~JHEHECH HE(HEHE HM(HE 3H;…t HM$H_^][SH HH9ǃH臍H [̐SH HH9ǃHGH [`SVWH H5H=H BHLL3H\H uBHHH HLI;H HH dLLHHHغH A3BHH`H/BH _^[̰SWH(HT$HHٺH fA!BH RdH BHHL$HlHH A;HH?tHG;t H@H(_[0H H(H`AH(SH HٺH @/AHP`HLH XMtHI9tIH HALIH [SWH(HHH 8@@HP`LH3H(_[̐SUVWATAUH(HH ?@fdždžfdžH H Dn@HH$HHHB@H芊kHHH9'HH HtHH9t H @@HHHH0H=qH ?HLHHHH`L-IAUHH-CL%I $?HLHHj?HHAUHH-%I $l?HLHH3?HHܹAUHH-މI $5?HLHH?HH}H(A]A\_^][SUVWH(IHHH o>HH؉H >>HPhLHHȅu HN0H>H9LH(_^][`SUVWATAUHHHl$ HHHeH9HH]H[;HLLL-VnII>HII>LA<$H ;==HPhIYHLHtIH9tHI=HHKȅt$H9IRE1fffffH;HLȅ) HM6!HMHtHp9LEHe(A]A\_^][SUVWATAUH8Hi Hl$ Hm HMHtH$9LH8A]A\_^][ЀSH HH9aǃHH [̠SUVWATAUAVH0IH3fL$ ?HO(H9LHHO(H93LHH p;HH D_<;HO0H<93LH lH;HH ;HHhHgfD$ HL$ uVH?H :l;HPhHHH HtHH9t H ;HH轅AH~HH褅u"H;HLH誅HH臅 HHzHH 2kH:HHL%/:I $:HHU`HAHL-HtIEH9tHIM:H>I $q:LIT$hL5HAHHtIEH9t IM:HHȅt8IT$hHALMtIEI9tIIMO:LHU`HoH0A^A]A\_^][~SH HHHtL4HIH [HH [}SWH(HٲHbHy8HsHLHtIH9tHI9HHt 93H H(_[p}SH HH9ǃHHHH [HH [@}SUVWATH HfL%A$HH2HH 88HHhHHLHH誂H=3HfA$LHH|HfA$LHHRLIHhHHfA$LHHLsIHhHHfA$LHHL+IHhHHfA$LHH誁LIHhHHfA$LHHrLIHhHHfA$LHH:LIHhHHfA$LHHLcIHhHHfA$LHHʀH9HHHhHLHHIH A\_^][HH A\_^][̠zSVWH0HHH d?6HHHHD$ HT$ H )L6HHH9HH0_^[0zSUVWH(IHHH e5HH蘀H 4o5HPhLH׹H_ȅu HO0HL5H9HH(_^][̰yH(H(̠ySH HٺH L45HNH [̀yHHpySH HٺH 34HPhHLH MtHI9tIH 4LIH [ ySWH(HHH 3+4HPhLHH(_[xSH HHK0ȅuHC0NfH D33HPhHbHLHtIH9tHI3HȀ9H [̀xH(H03H(pxSVWH H 23HHɻHH 3HAE333HȅHHHDD@HHHHpHAHxHAHHAHHA HHA(HH]ȅtbAAH9HHHpHAHxHAHHAHHA HHA(H$HȅtdAAHHHHpHAHxHAHHAHHA HHA(HfHȅ~H3H ȅOAH;HͼLIIHHH+LE3HHLAHLHtIH9tHI.HH9HHHtH9LLIIHHtH9LLHH*yHHHpHAHxHAHHAHHA HHA(HL.AAHMPHMPHHpHAHxHAHHAHHA HHA(HfHȅHHM8HM8HHHAHHAHHHH~DD@HMHMHHpHAHxHAHHAHHA HHA(HLHpIR-IDHA\_^][̀qH3HD$PHD$XHD$`HD$hHD$pHD$xHD$ HD$(H `c,LIHD$ ICHD$(ICHD$0ICHD$8IC HD$@IC(HD$HHL$ HHD$PHAHD$XHAHD$`HAHD$hHA HD$pHA(HD$xHD$PH)P*D@+HĈ̰p̰pSWH(HHvHHt-ƃHϿL?HHMAƃH(_[`pPpSH`HT$xH3HD$ HD$(HD$8HD$HHL$xHHD$ HAHD$(HAHD$0HAHD$8HA HD$@HA(HD$HHA0HD$PHT$ H HL$xٽHH *uuHuH`[̠oSWH(HHHH?G<uuHCuHH(_[HH(_[`oH(VH(PoH(HH )Hu3H JH)H( oSVWH IHHL$@HL$@d HL<E33H LHFLIIHAQH _^[nSVWH IHHL$@HL$@ HL;E33H% LHFLIIHAQH _^[̀nSWHH)t$0H%H 'u(Ht$ HT$ H L(LHH(t$0HH_[ nSH Hٺ%H |'7(HfH [nSWH(HHP%H D''HH_HH HtHH9t H 'HЀ;HH(_[̠mSVWH@)t$0HfWD$(A8A@<u{HP9HHt$(LLHbȅtDt$(%H &'Ht$ HT$ H f'LHH_(t$0H@_^[lSVWH@)t$0H%H &&HHH-H5~HH&0HHHH&\Ht$ HT$ H&LHH(t$0H@_^[PlSVWH@)t$0H%H e%%HHH}H5ΗHH;&0HHWHH&XHD$ HT$ H&LHH(t$0H@_^[̰kSH Hٺ%H $O%HH׭LH mMtHI9tIH e%LfIH [`kSWH(HH%H X$$HLHPH(_[0kSH Hٺ%H $$HH7LH MtHI9tIH $LfIH [jSH HT$8Hٺ%H #r$H dH[$HHtAHL$8HH Ht HH;t3Ht;HPHt 9H [`jSUVWATH@)t$0HHH5$#%H#H dH#HHHH-tHHM#0?%Hd#HHL%HA$HHM#f.r4HHA$HHM#D$ HT$ HMt#zHHM^#0HL%|HA$HHM9#f.sH:HHA$HHM#D$(HT$(HM#3@(t$0H@A\_^][iSUVWATH0)t$ HH@HH9LyHH J"HXHH "H/HtlL%nH ʻ"HMHH}HHHH^5ܥ;H;HDH@HVH9LǰHH !H`HHn!H/HtlL%mH c!HMHH*}HHHH^5*;Hj;HH@HH9LHH C HPHH H/HtjL%MmH ξ HMHHx}HH@H?H-&mH /z HLHHA?HH(t$ H0A\_^][fH(HPHt 9H(̰fSWH(HH%H HHLH@H(_[̀fSH Hٺ%H HH'HH uH [@fSWHH)t$0H%H EHt$ HT$ H LHH(t$0HH_[eSH Hٺ%H LHHgHH (H [̠eSWHH)t$0H%H Ht$ HT$ H \LHHТ(t$0HH_[@eSH Hٺ%H HHHH hH [eSWHH)t$0H%H 2Ht$ HT$ H LHH(t$0HH_[̠dSH Hٺ%H _HHHH 5H [`dSUVWATAUAVAWH)t$p0H \HL-a]Ll$@ItHIiHHHD$HHHHH}LHHLiM#L=L|$PIHIHfWt$8HT$8IHL-;Ll$XHǻHD$`HjHHHAUHHD$hLLHIHغ%H lLIHLM#IkHHL$@^Ht$0HT$0I(HHL$`H HHHAULLHIHD$hIHLRM+ILHL$@Ht$(HT$(IHL=gHH ?HLM3HL|$`I7HLE3HHLLIILl$hAUIHLM#H\$PH GHHL$@:Ht$ HT$ H HIHHHHD$XLLHIAUIHbLcM+H ALHL$@H#%Hp L=JfHH DHLM3HHL$HH HLAHHǮLLIILd$hA$IHLI+H Ҵ%HHD$@HHHL$`H H3HgLLHHA$IHP(t$pHĈA_A^A]A\_^][p`HA``SVWH IIHHKHKHHKHHK0HT$`CHH _^[ `SVWH IIHHKHKHHKHHK HT$`HK(HT$hsHK@HT$peCHH _^[_HA̰_SVWH IIHHKHKH HKHHK HT$`HK(HT$hHK8HT$pCHH _^[P_HA@P_AH@_HA80_HA0 _HA(_HA _HA^SVWH IHHL$@HL$@HHraALHLHFLIIHAQH _^[̠^̐^̀^p^SVWH IHHL$@HL$@4HL)E33HULHFLIIHAQH _^[ ^SVWH IHHL$@HL$@HLB$E33HLHFLIIHAQH _^[]SVWH IHHL$@HL$@tHL$E33HLHFLIIHAQH _^[̀]SVWH IHHL$@HL$@HHALHH.LHFLIIHAQH _^[0]H(@H Hh8HH(]SH Hٺ@H _HhHXH [\\\H(ED‹IBLIJARH(̰\H(3u3IBLIHAPH(̀\H(HH(p\HAp\SUHXHl$ )u HHefWuEHEȅu.Ht!H$LHLuEu*!H JH*H τBE(u He8][[[SUVWH8IHHH H;Hu3&HHHHH3H;t!HH 8HH2HHH HHPpD$ HT$ H oH8_^][ [SWH8HHL͂Ht HI;t3HtIH HtHH9t H HHHD$(HT$(H t5DH=aHHHPxD$ HT$ HH8_[̀Z̀ZpZSH@)t$0HfWD$ L$ HKȅt#H[HD$ 0LH HD$ 0L3@(t$0H@[Zf. v  vf.vfWbf.v\ ^ Bf. r f.rY\ v^ ~X ~pYhf.vbYX^Bf. DrRf.r^H\2Y:X:YSH0)t$ L$HHQHHD$H0LH(t$ H0[XH8HfWD$ HT$ HD$ H8̰XSVWH HHHȅt fW3k;#HP(AH HHع HLL H=f.v2H _^[ XH( ^ YH(WWH8HfWD$ HT$ Hr]D$ H8WUH0Hl$ HeHE^ YAHEHEHe]pWH(^d _^H(PWSUWH0Hl$ HH]8HHeEHȅt fW3c?# HP(AH;3H ^  ב^ EHe_][̰V̠VSH0)t$ L$HHIHHD$H0LHq(t$ H0[`VH(HLHH=4HHaHaHtHH9tHHhHDH=;HHH`~HHIiQ\HȅtH HH )fH !HH?IH;HHHsqHtHH;t3@;]?HH{;HpHlHkHH'3HL-PH .q!HMIHHH,I$09HOHH Ht;I$0H HHӃ?HH]fffffH >HLȅHUH ;pHtH8HLHe(A]A\_^][@LSH HIIP`HH=H}ȅt)HH HtH3OHHH [HH [KH(HHtD:HLoHt HI;t33HtHH oH(̠KH(H ͙xHt3H(̀KSUWH0Hl$ HHH}0HeEHUHHPHt HHPxHH nHtHH9tHH HHPHHUHHHe_][JSUVWH8Hl$ HHH]@HeEHUHHPHH HH nHtHH9t H HАH8HUHHe_^][pJSWH(H9HHt4H09;H}LOMHHIH(_[HH(_[ JSVWH HHݑH5LH OmHLHHaHHH _^[ISWH(HH=HHMHt&HH=HtHaLHHH(_[HH(_[̀ISWH(HHPHt ILHHOWH(_[@ISH HںdH ;C$H [ IH(dH SHH(ISUVWH(HdH DHkHeH5vH-kHMHLHHHH!H5KHMHLHHHH H(_^][`HHaKHPHH(H09H(@HSUVWATAUAVAWHHHl$ LHeHEI09H=tH8HxLHHLHH}eDHy?HLHH HtHH9tHH HH LIL=u;HAH5r|A<$HIHAHHUHHSL9HItIdH HI3I|HAHI3ItȅtIA>IAHHA>Hu Ht3HHeftA<$IčI09IJffH?HLȅHUH +iHtH8HLHe(A_A^A]A\_^][FSUVWATAUH(HH8H TvHH lHLHH=dH !HHHH 3&LH+H=AHH}H HLL3HL-4HH}H aHLM3HH ߖZHLLHHHIH(A]A\_^][ESUVWATH@Hl$ HHeHEdH &H=Rq8HtH3Htȅu';HrL؀>HV0IIPHȅt6H؀;HȅHHLHH}@H?HLHH dHtHH9tHH HV0H DHtHH9t H HЀ:HI$IMPHȅt&8p8HHх/fffffffH)?HLȅ3HUH +fHtH8HLHe A\_^][@CSWH(HHH T(HAHHEHHc~H(_[CSVWH HHUH5EH geHLHHHH-H _^[̰BSWH(HG uH_HHAHOH9H(_[pBSUWH0Hl$ HHH}0HeEHUHnHOHt HHPxHH dHtHH9tHH HHOHHUH.fHe_][ASUVWH8Hl$ HHH]@HeEHUHHsHHHH dHtHH9t H wHH,HUHHe_^][pAH(A t  H(PASUVWATAUHXHl$ HHH]pHeHEHKHt 9HC3}H[HH ٍ;HH5H&8HLHH] :H;HLHH cHtHH9tH Y}Hٹ;HLȅuHU H b5HtH8HLMLepAD$ u HΧL( HL(HH0MHUH bHH ;bHM3HLǺHLH3IHk8HDoAHH=LepI|$Ht$H b)HHLIHOWHe8A]A\_^][`?SUVWATH AHH^H@~ H;H-AL%VaI $HLHHl?HHMH=AI $uHLHHSH HH я4HtHHAHH [HH [̠>A ̐>H(A t~~H(p>SH HYA tI @BЀ;HwH [0>SVWH HHH5@H _:HLHHHHH _^[=SWH(HHlH UNHE3HH?HH3xH(_[̠=SVWH HHHHHȅuHHoLIHyH _^[P=HP=H@=SWH(HHHHH OHHHt,;HHg?HHi?HH(_[HH(_[<SUVWATAUAVAWHHILL3HD$0HD$8HD$ oLM IQȅuIILC"LI 3L;toHKLH5H(IIH ]HL3H LǺHLH3HIpI 3L;t%3HD$0HD$8L^HT$0I\I?IIT$E3L\$ L\$(MIHL$ LH^HT$ IIHHA_A^A]A\_^][`;SH0LD$PHHT$PHRHL$ HL$ HHHAHCHH0[ ;H(HT$8HL$8HIyH(;H(H(:SVWH HHHHHȅuHH?LpIHvH _^[̠:H(H(̐:H(HH(̀:HAp:H(HH(`:P:HA@:SUVWATHHl$ IHHHeLe8ILAIIHHE E3LL3HHEHE HHEHE HE@LEHUHQZ} LIԋHHHMHE8HHH@HAeH} ~ HM-H} ~JHEHEOH HE0HEHE(HM0HE(3H;…t HM$fHA\_^][8SH0HD$ HH 0ZHHu39xH H;LD$ HHT$ H H0[̐8SH HHxH XHHQH [`8Ht9HAPHt8HP@Hu3 H9HH08Ht 9HApHu3H9HHH8SUVWH8Hl$ HHH]@HeEHUHHs0HH>HH XHtHH9t H HHlHUHHe_^][̐7SVWH HH|H HHH ɆtLHHmkH _^[@7SHPH3HD$8HD$@HD$H|H HH6oHH TLIHD$ ICHD$(ICHD$0HL$ HHD$8HAHD$@HAHD$HHD$8HP[̰6SUVWH)$)$Hȅ3H$H$H$|H DHHH5^nHH-zHHMLIHD$8ICHD$@ICHD$HHL$8HH$HAH$HAH$H$p3H$H$H$HHHHMLIHD$ ICHD$(ICHD$0HL$ HH$HAH$HAH$H$X3HD$PHD$XHD$`HL$PzHL$PHHD$hHAHD$pHAHD$xHHT$hHMLHHh($($H_^][4SUWH0Hl$ HHH}0HeEHUHHO0Ht HHPxHH !UHtHH9tHH 1HHO0HHUH^fHe_][P4SWHHHHٺ|H HH#lHH ALIHD$ ICHD$(ICHD$0HL$ HHHAHCHAHCHHH_[3SUVWATAUH(HL%*IHHtL9et HIAH@0HHHtL9et HIHp0HH8L-TIMHHH~LHHNVHHtL9et HIHp0H͘H8IMHHH3LHHNVHHtL9et HI}Hp0HH8IMNHHHLHHNVH(A]A\_^][̠2SHPH3HD$8HD$@HD$H|H +HHFjHH dLIHD$ ICHD$(ICHD$0HL$ HHD$8HAHD$@HAHD$HHD$8@HP[2SUVWH)$)$H ȅ3H$H$H$|H THHH5niHH-HHM&LIHD$8ICHD$@ICHD$HHL$8HH$HAH$HAH$H$03H$H$H$HHHHMLIHD$ ICHD$(ICHD$0HL$ HH$HAH$HAH$H$X3HD$PHD$XHD$`HL$PuHL$PHHD$hHAHD$pHAHD$xHHT$hHMLHHc($($H_^][00SUVWH)$)$Hȅ3H$H$H$|H dHHH5~gHH-~HHM6LIHD$8ICHD$@ICHD$HHL$8HH$HAH$HAH$H$03H$H$H$HHHHMLIHD$ ICHD$(ICHD$0HL$ HH$HAH$HAH$H$P3HD$PHD$XHD$`HL$PsHL$PHHD$hHAHD$pHAHD$xHHT$hHMLHH b($($H_^][P.H(eH(@.SUVWATAUH(HL H |趸HH 4C觸HL-5/HcH 7|HLM3H蟷H `| HHHqLLHIJeHغ|H HHH(A]A\_^][̀-SHPH3HD$8HD$@HD$H|H NHHdHH {LIHD$ ICHD$(ICHD$0HL$ HHD$8HAHD$@HAHD$HHD$8@HP[,SWH(HH}H (HLH `H(_[,SH Hٺ}H HHdLH ]LMtHI9tIH LfIH [p,SWH(HH}H HLH_H(_[@,SH Hٺ}H LHHgcLH KMtHI9tIH LfIH [+SUVWATH HAHHHH;}H \HHL%bHA$HH-2KHtHEH9tHHMhHDHHbHHtHEH9tHM6HHXȅuAHHA$LMtHEI9tIHMLHH^H A\_^][*SUVWATH H@HH|HH?}H HHA$LMtHEI9tIHMLHH\H A\_^][)H(`H()SUVWATAUAVAWHhHL(HIHD$ H誳LHP?HD$(H蓳HHqHD$0HH0Ho*L5^Lt$8H wHD$@HHML3HlL5lLt$HL=ytIHLE3HHAHmHD$PLLIIHغ}H YLIHOLM+HL$ H LHL$(賲HHD$0HH0H)HL$@H HLL$8L3H褱IHLE3HHHD$HLLIIHD$PIHHhA_A^A]A\_^][ (SUVWH(IH?HONHHHHAHPxHHWHHH G@(HHHAHPxHHWHHH FHtHH9tH 6H@ŅuH(GGfH(_^][`'SVWH Hڀ;s DFDf$Hղ+E3DƋHHHHHܰȅHHH述ȅHՋHH袰ȅHHH腰ȅu~HHHlȅueHHHSȅuLHHH:ȅu3H|HH!ȅuHkHHȅtH _^[ &SVWH HHjH5'H tZHLHH!HH]jH _^[%H8Hu3D$ HT$ H [ENH8̠%SH H EHH蔵HdH [À%̀%SH H EHHTH$H [`%`%SVWHP3HD$@H sHHu3H;HLHHLHD$@HL$@.iȅt3HٚHLHiHHH 3H;t3HUZHH )H ǜrH`HAHD$ HAHD$(VLHL$ HHD$0HAHD$8LD$0HHZHH;HCbHHP_^[ $SH H DHHijHH [$#SVWHP3HD$@H cqHHu3H;HLHvHLHD$@HL$@gȅt3HQHLHxgH&HH 3H;t3HXHH )H 'H`HAHD$ HAHD$( ULHL$ HHD$0HAHD$8LD$0HHHHw;H`HHP_^[̰"HA̰"H(HCH(̠"HA̐"̀"SWH8HH PA;ÅtHOɪȅt:fÅuPHO谪ȅu@HOHD$(D$ E3AHOHD$(D$ E3AeH8_[!H8HP`ȉL$ HT$ H @H8!H(H @pf3ɅH(̰!H(HH(̠!̐!̀!H(HH(p!H8H e?f3ɅL$ HT$ H ?H8@!HA0!SUVWHHHHlI8H0JHWL8HMA8HJHu4H HH苯H舯DH]H0HoAÅun _D$0HT$0H Q>HH >hHL3H`LǺHPLH3HHȅuHD$(D$ AE3H4H HHH_^][H8Ht#H > L83HMAfW3f.R3D$ HT$ H =H8pSVWH@ HH0QYD$0HT$0H =KHH HSLIIHH]8HE3HU(HLHH}@H[ȅHH ?eH3Ht@ȅH5[?HHE HM A$ȅkHHEHM[ȅMHL E3HHLAHH dHH]H3HBȅtE0HHLHE0fHM:HH vdH3H?ȅH5Z?HHEHMA$ȅHHEHMZȅtxHL E3HHLAHH c&HH]P3HBȅtE0HHLHE0HMPHtH9LHM@HtH9LL]8IIHM8HtHċ9LE0He`A\_^][SUVWATH0Hi Hl$ Hm HMHHtHl9LH0A\_^][SUVWATH0Hi Hl$ Hm HMPHtH89LH0A\_^][SUVWATH0Hi Hl$ Hm HM@HtH9LH0A\_^][SUVWATH0Hi Hl$ Hm HM8HtHЊ9LH0A\_^][UH@Hl$ )uHefWuHyH}@Ht*HH U4Lq83HMAuE(uHe ]̠H(HUyH@HH 2-f3ɅH(pSVWH@HpH?HH 2fuf"ufuf uf3HxH0D$0HT$0H ;2HH 1RHL3HJLH3 HD$(D$ E3AH4H #HH@_^[̐H8H 1fуt 3D$ HT$ H 1H8P@0H8H %1f3ɅL$ HT$ H s1fH8SVWH@HbwH>HH 0*f3ɅH>wH0u3D$0HT$0H 0HH D0觿HL3H蟿LH3bHD$(D$ E3AHT4H x#HH@_^[0SVWH@HvH1=HH /Jf3ɅHnvH0t輠 譠fD$0HT$0H /HH Q/贾HL3H謾LH3oHD$(D$ E3AHa4H 0HH@_^[PH8H /pf3ɅL$ HT$ H c/VH8  SH3H$H$3H$H$HL.Ht HI;t3Ht0H.H ׽fgȉL$PHT$PH ýHLt/Ht HI;t3HHL/Ht HI;t3Ht7H.H gBfTL$8HT$8H L HL.Ht HI;t3Ht,H-H 諞D$0HT$0H HL.Ht HI;t3Ht.H.H ȼHhHD$(HT$(H 趼HLw.Ht HI;t3HHL].Ht HI;t3Ht9HB.H ZATL$ HT$ H @HL.Ht HI;t3H>/HfDH -} 薝D$$HT$$H -ӻfDH-H 豻LAD$@ACD$DACD$HAC D$LHL$@HH$HAH$H$HH$HAH$H$HHD$`HAHD$hHT$`HL$pHT$pH 'HĠ[HSH H |,臺HH4HH [SVWH0HH{HHSH +y@0H;sgHTHt&H ,膺L?83HMA3@ƅt 3Ʌ3ɉL$ HT$ H $+H0_^[80 SH H \+gHHHH [SVWH0HH{HHSH n*Y@0H;sgHTHt&H *fL'83HMA3@ƅt 3Ʌ3ɉL$ HT$ H *H0_^[PSH H |*臸HH4HH [00H8H %)耸f3ɅL$ HT$ H s)fH8SUVWATH0HMt(IH )_L(83HMA3HHk;~k34H Ձ耷LDHcH;HLI$H;tRHCH;HTHt;H (蟷t(;|D$ HT$ H (>DD$$HT$$H l(_DD$(HT$(H L(?H0A\_^][]  SH H (ǶHHtHDH [ H8H u'жf3ɅL$ HT$ H '趶H8̐ SVWH@HmHa4HH 'zf3ɅHmH0t ݗfD$0HT$0H &0HH &HL3HܵLH3蟐HD$(D$ E3AH4H `HH@_^[̰ ̠ ̐ H H̀ SUVWHHl$0HeHEhHDž3HHExHEpHEPHE0H iTHHu3H|;HLH|HLHHJȅt3H|HLD$ A@E33HJHH HuxHMpHMxHEp3H;…t39H;HEhH}huHHDžH]hHEh8HUhE3E3HMPJ;HMPHHE0HAHE8HAHE@HU0HIH}h_H )H }7H`HAHEHAHEr7LHMHHE HAHE(LE HH%HH;HCH HM8 H}htHB{HEh8HMhLfHH_^][SUVWHHHi0Hl$0Hm0H}htHzHEh8HMhLHH_^][SH H <$GHHHIJH [SH H #HH贓H脲H [àSUVWHHl$0HeHEhHDžHExHEp3HEPHE0HL]QHt HI;t3Hu3H ;Q讱D$ A@E33GH)H HuxHMpHMxHEp3H;…t3=H8HEhH}huHHDžH]hHEh8HUhE3E3HMP1G;HMPHHE0HAHE8HAHE@HU0HGH}hsH )H zKH`HAHEHAHE4LHMHHE HAHE(LE HH9HH;H"@H HM9!H}htHZxHEh8HMhLfHH_^][SUVWHHHi0Hl$0Hm0H}htHxHEh8HMhLHH_^][PSWH(HHu30H NZH3HBȅt3 HHVH(_[SVWHE3L$L$L$L$L$L$L$L$LHH$H QM̮HH$HH$HAH$HAH$HAH$HA H$HA(H$H$HDH *N]HHDHDH3D$ 3fWfWH$DLH$HHD$pHAHD$xHAH$HAH$LL$pE3HHAHHP`HL$PTDH M谭HHL$PHHD$0HAHD$8HAHD$@AD$HHD$0HD$(=3D$ /3AHCHHCHH_^[SH H HHĎH蔭H [SUVWHIH3H$XH$`H$hH$pH$xH$3H$H$H$H$(H$0H$H$H$H$H$H$HD$hHD$pHD$PHD$ HD$(H$(,@H$(HH$XHAH$`HAH$hHAH$pHA H$xHA(H$>H?ȅH?H?H?DD@H$?H$HH$XHAH$`HAH$hHAH$pHA H$xHA(H$HH^?ȅtjAAH$9?H$HH$XHAH$`HAH$hHAH$pHA H$xHA(H$H>ȅtmAAH$>H$HH$XHAH$`HAH$hHAH$pHA H$xHA(H$THw>ȅtdAAHL$hE>HL$hHH$XHAH$`HAH$hHAH$pHA H$xHA(H$H#>ȅHHL$P>HL$PHH$HAH$HAH$H$=H$=H$=DD@HL$ c=HL$ HH$XHAH$`HAH$hHAH$pHA H$xHA(H$L HH$XH蠩HHĨ_^][H(HH "=Ht H9tH谨8H0HuH(HH(̐̐SWH(HH <CHHHHH(_[`PH(4H r賧HH(0SWH(HH 0<賧HHHUHH(_[SUVWH8HHH;GHt HH;t33HtiH-GHHMr3@HHMY03҅@ƅt…t@ƅt …t\$ H aHT$ H8_^][PSH H 触HHTH$H [0HA0 H(H#H(HApSUWH`Hl$ IHe3HU HU(HU0HUHU;CHQp:HMHMHHE HAHE(HAHE0RfHHM \;L[8HPL;uMtHu3 IIPHt 3;C"fH=yHHM ȅu fHM HNHM He@_][SUWH0Hi Hl$ Hm HHM H0_][SVWH HH:H ɤHH^HOpH芤H53H ;H(8H(3ɃM HU H HE HM+HM HtHrZ9LfHEHe0_][SUWH0Hi Hl$ Hm HM HtH5Z9LH0_][HHAH(H裐H(SUVWH8HH4H ZiHHH;Hu 3fHH f0葐HtHUY8HLHHvHHLP@HH 3HL3H+LH3jHM 8H 8H 8HHD$(D$ E3E3HHfH8_^][HSUVWATAUAVH@Hں4H YFLIH;_H=l.HHAL3I"ȅt4HH */UHt H!X8HLHHL3I"ȅZA}I&ȅ!I&=H^FL I"ȉL$8HHT$8H ׎HI"ȉL$4HT$4H 跎HI"ȉL$0HT$0H 藎HH KHL3HCLƺH3LǺH#LI3hHfDHEH8H HM3HݍLH3hHfHIEH(I$HI$HH *荍HL3H腍LƺHuLH38hH8H 8H 8H1HD$(D$ E3E3HIH@A^A]A\_^][ SH HٺH 菌H HLH MtHI9tIH 襌LfIH [SWH(HHH +H LHH(_[̠SH HT$8HH <Ht H9tH*HX0HL$8cHH )HtHH9t H HЀ;HK譋H [@SH HٺH H(HLH MtHI9tIH 蕋LfIH [SWH(HHH H(LHH(_[H8HI0LHD$`HD$ AR`H8̠H8HI0LHD$`HD$ ARhH8̀SWH(HH *賊HH!HO0HsHH(_[@SUVWATAUAVAWHXHBL HHD$ HeHHXHD$(HeHH)L-Ll$0H)HD$8HHML3H~dL-G!Ll$@L53)IۉHL3HAUL=%LLHIAHغH ߈rLI HhLAAM#HL$ H dHHL$(dHH2HL$8H =HLL$0L3HcI8HL3HHD$@LLHIAI(HHXA_A^A]A\_^][SH HT$8HH Ht H9tHڈHX0HL$8HH HtHH9t H 謈HЀ;HK]H [`HPSH HHH [@0SUWH@Hl$ HUHHeHZH 'WLP83HMAHEHP8HLHH &襇H3Hȅ;Hxȅu$HȅuHȅH ~YHHcH?HHL?Hc HغH RQHP:LH H LII;HH HEHM2!HMHtHO9LHUHHHEHe _][SUWH0Hi Hl$ Hm HMHtHO9LH0_][ppH`SUWH0Hl$ HHH}0HeEHUH>HO0Ht HHPxHH HtHH9tHH хHHO0H肅HUHfHe_][SUVWH8Hl$ HHH]@HeEHUH譅Hs0HH`HH 4HtHH9t H GHHHUHxHe_^][`SUVWH(HHHw0Ht)H ՄHHHofLHHNVfH(_^][ SH HٺH ̃_H0H H [SWH(HHH H0LHH(_[SUVWATAUAVH H;L(H d_LH U_HH=cH H "HLL3HM^L5FH H #蓃HLM3H ^H "范HLL3H8LLII HغH "H0HH A^A]A\_^][SWH(HHٺH HۂH0LH@H(_[̠SUVWH(Ha HH辂HHt?H~0Ht6H:H(Ht'H 袂HHHH{XLMt3IIP@HHl$$%ZLLHZȅu9H4HD$ HT$ H }LHH'X |$$8H Ff|HHH-}4HEH9NXȅu{H xc|HHHEHHK|H@4HHK |H54HHK{HP8HXHK {H9HtHH3H9A*8H E{HH3H9WH8_^][ H(H3H3H(SVWH HLu=ƆLH]3HH 6{HAHHVHHH _^[ðSUVWH8HHP9u3fD$$HL$$]T$$H\H8H DzHHH-2HEH9iuunNzH HX2H9\HHK2HD$ HT$ H \z?LHHUHHEH9VH8_^][SWH(HٺH +yyHH@9sH;uH@93DH@9H1H@99H(_[PSH HٺH xgyHH [0SUVWH(AHH txyHH@9H;uH@93DH@9HuH@9DƋH(_^][̰SH ںH wxH@9DH [̀H(H wCxH@9H(`H(H w;x3H(@SVWH H 2xHHH5:wHwH@HHwH 9HwHwH`H _^[SH HvH wwH BwH@H [̐SWH(HH=vH3wHvHH;HLH MtHI9tIH wLIH(_[ SVWH HHH5uHvHzvHP;LHH _^[SWH(HH=uHSvHvHP;HLH MtHI9tIH 1vLIH(_[`SVWH HHH5uHuHuHH;LHH _^[SUVWATAUAVAWHXHH\$ HHD$(HhuHHHI HD$03HL- Ll$83HAUL% Ld$@HA$L$I;H mPHL5I[PL=TLLHHAHغH ttHHHHHtHL$(H tHHHD$ 3HHD$03HAUHA$HL%rI $OL-B ;LHHAUHL$(H MtHHHD$ 3HHD$03HHD$8HHD$@L%I;H fOHI[OLLHHAHPHHsHD$(HsHHHD$ 3HHD$03HHD$8HHD$@HI $N;LHHAUHXA_A^A]A\_^][H(H r#sHH(SWH(H=H#sHHPC(HtH9;tHHsH@H $rrHHrH(_[pH(TH(`SH HٺH q_rHHHH rH [ SH HٺH |qrHHLH MtHI9tIH %rLfIH [SVWH0HH qqH@ljD$ HT$ H qLHHH0_^[̀SH HٺH pOqHHHH qH [@SVWH0HH gppH@ljD$ HT$ H WJqLHHCH0_^[SH HٺH ppHH'H [SWH(HHH o[pHLHH(_[̐SWHHHHٺH opHHHH IdpLIHD$ ICHD$(ICHD$0ICHD$8HL$ HHHAHCHAHCHAHCHHH_[SWH(HHH n{oHLHH(_[SVWH HHH n:oHHH qoLHHH _^[̀SWH(HHH HnnHLH@H(_[PSH HٺH nnHH'LH }MtHI9tIH nLfIH [SWH(HHH m;nHLHH(_[SH HٺH lmmHHLH MtHI9tIH nLfIH [̀SWH(HHH mmHLHH(_[PSH HٺH l_mHHH [ SWH(HH6HHBHHH (mHtHPHlH(_[SUVWATAUHHHPHnH llHHH*Hu~HHHLkHtIH9tHIlH[Gȅu&HHHH luHP93,HXHEHu'H H #lHHHHk@HXHHYHH HtHH9t H kHЀ;HLXHHHHL-gHtIEH9tHIMkHUFȅu~HHHHtIEH9tHIMekHfH!H(HHLMtIEI9tIIM)kLHH+IH6fDHHPHHtIEH9tIMjHA<$IHX9HHHu-HX9HuHP93VHX9HLHxL8H@8@4HHHHHHLH Mt IH;tE3MHX9gHt*HH"HH i3HD$0HD$8HD$@HD$HbD$ \\ LHL$0HL$0HH$HAH$HAH$HAH$HH$H ' JiLHHC~3HD$PHD$XHD$`HD$h HL$PHL$PHHD$pHAHD$xHAH$HAH$HHT$pH hLHHHĸA]A\_^][0SUVWH(HH-~gHM0hHM"hHQH: HH 0 hHHH3HL=L}P>HAL-LmX>3HAUL/I;H XAHIMAL%FLLHHA$HغH deLLu`IHeHM8H eHHHE@>3HHEH>HA>3HAULI;L=&I@HHM0@LLHHA$IHeHM8H eLIHE@A}3IHEHA}IHEPA}3IHEXLM#I1@HHE0H"@HHPHEhL=-H dHMLEh3H?H\$ MLHIIH?dHE8H[dHHHE@HupHHH 5dHAHH?>HHHEHHHExHup>HHH>3HL I;H )?HL5LI?L LLLHHALe`I$HWcL-LL=IbcHHAUHAH>3H>HHEx>3HHLbI;H k>HI`>LLHHHI$HbIbHHAUADm L5HU Ib>HHH>HHEx>3HHLI;I=HH=LLHHHI$H bI-bHHHDmHUINb>HHLAU>HHEx>3HHL,I;I)=HLI=LLHHHI$HjaIaHHH3HEHEHE HE( YHMGHhHUH a>HHAU>HHEx>3HHLqI;H fI+H '9HI9HL5zI]HE3A/3HAL-LLHHAUHغH \;]LI$H0]LI+H 8HHL$ 8HI*]HE3A/3HALLHHAUI$H\H8A_A^A]A\_^][PH(H(@HA80H(H0c\H( SH HHK8?\HC@H [SUVWH(AIHHHsHK0H[HK8H[k,H(_^][SVWH IHHH'HK0H[HK8H[C,H _^[̀H(H(pA,pQ,`SVWH@H3H$H$H$ H$(H$0H$83H$H$H$3H$H$H$3H$H$H$3H$H$H$H$H$HD$hHD$PHD$ HD$(HS8Hu 3eDH=HYZHuCC,u4HS8H Z8H >ZH؋H9H3 HC8HtH98t HH Z8HX3H$H$H$ H$(H$0H$8H$H= ;HH$H$HH$HAH$HAH$H$H;HH$H$HH$HAH$HAH$H$HV;HHL$hHL$hHH$HAH$HAH$H$CH;HHL$PHL$PHH$HAH$HAH$H$HH lXHH$HHD$ HAHD$(HAHD$0HAHD$8HA HD$@HA(HD$HHT$ H7H@H@_^[ SWH8)t$ HHK8Hu 3xfHC@HiHHt HH;t3Ht(HS8H }HtHH9t H WHHK8HMHt HH;t3HC,u6HS8H "W0H1DHu3HS8H ZW0HDH~HS8H 'W0HòD)HKHS8H=HVHuL[8IIP@H!HC8HtH98t HHV8HPH@HMVH(t$ H8_[̀UH0Hl$ HeEHHCHt&HH VL783HMA3EEHe] UH0Hl$ HeEHLHHt&HH VL83HMA3EEHe]HA0̰SVWH AIHHK0UHK8H Us,H _^[̀*A^ pQ`H(HLUH(PSHPH3HD$ HD$(HBHD$ HBHD$(HBHD$0HB HD$8HB(HD$@HB0HD$HLHT$ HUHHP[H(HLiTH(H(g6H(еSUVWATAUH8IIHLL-H$IM8/H;tH|$ LLHI 6H HSLH SHHA<$ML$HH|$ LHHPxHHtIEH9tHIMkSHH HMD$d1H8A]A\_^][SVWH IHHH l.H;uLHHM5H _^[SUVWATAUH(ILLIH Ht HH;t3fHuLII4H H>.HHHHLHDE}3E3E3HY/HH g2RHHHLLIHPpHH HtHH9tHH RHH @QHHHAUDF D+E3H.HKHQHH(A]A\_^][̐H(HcQH(̀H(HCQH(pHA`H(HQH(PHA@SWH8HHٺH PPHH3HH PLIHD$ ICHD$(HL$ HHHAHCHH8_[вSWH(HHH O+PHLHH(_[̠SH HٺH \OOHHwLH MtHI9tIH PLfIH [PSVWH0HH NOHt$ HT$ H OLHHH0_^[SH HٺH N/OHHHH xOH [SVWH HHH GNNHHH 14OLHH-H _^[pSH HٺH MNHHHH ݿNH [0SWH(HHH M+NHLHH(_[SH HٺH \MMHHwLH ;MtHI9tIH NLfIH [̰SUVWATAUAVAWH0H MHH H\$PH(HH(HL%,Ld$XI $vMHHH}LHHL=L|$`I $?MHHAL5wMIHHHD$hHHHD$pHHHD$x3HLSI;L-IM8(HHL$P+(L%$L$LLHHA$HغH KhLHHH^LHL$XH yLHHAE3D|$8HH$HT$8H LHHHD$hHHD$p3HHD$xLI;H u'HHL$Ph'LLHHA$HHKHL$XH KHHHD$`ADd$4HHT$4H KHHHD$hHHHD$p3HHD$xLI;H &HHL$P&LLHHH$HHKHL$XH /KHHHD$`HHD$p3HHD$xLI;H T&HHL$PG&LLHHH$HHJHL$XH JHHHD$`3HD$@HD$H HL$@HHT$@H JHHHD$hHHD$p3HHD$xLI;H %HHL$P%LLHHH$HHIHL$XH IHHHD$`Dd$0H&HT$0H JHHHD$hHHD$p3HLd$xA$LSI;H $HHL$P$LLHHH$HH>IHL$XH YIHHHD$`IHHHD$hHHD$p3HA$LI;IMt$HHL$Pg$LLHHL$AHHHHL$XH HHHHD$`D|$,HT$,L$IMHHHHD$hHHD$p3HA$LCI;IM#HHL$P#LLHHAHH$HHL$XH ?HHHHD$`D|$(HT$(IM_HHHHD$hHL|$pA3HA$LI;IMI#HHL$P<#LLHHAHHGHL$XH GHHHD$`ADd$$HT$$IMGHHHD$hHA3HL|$xAL2I;IM"HHL$P"LLHHAH HGHD$XHGHHHD$`Dd$ HT$ IM>GHHHD$hHHD$p3HALI;IM*"HHD$PH"LLHHAH(HtFHĘA_A^A]A\_^][`SVWH0HH E*FH@ljD$ HT$ H zFLHHsH0_^[SH HٺH HHD$@HD$8HD$0H\$(Hl$ E3A$HH(LH ۱MtHI9tIH ?LIHXA]A\_^][̰H(MH€8MIH!H(̐H(H(̀HHAHBHAp`SWH8HBHD$ HBHD$(HT$ HHHBHAHH8_[ HHBH$HBHD$H$HHHBHAHHHuIHI@HAH(fHBH$HBHD$H$HHHBHAHHðSHPH3HD$0HD$8HD$@HHD$ HBHD$(HT$ HL$0HL$0HHHAHCHAHCHHP[PSWH8HT$XHH\$Xu &|HCHD$ HCHD$(HL$ HHHAHGHH8_[H(u 3HHu3 H~H(СH(u H=H HOH(̰H(u3 H.H(̐SH0HًStHH;u@vHCHD$ HT$ H HNLDNj5FFH(_^][DAHL3HDAHeE33HSVWH AH|}| F+;HNDNjFFH _^[̐DAH3H̀SVWH0AHم|}| C+;} ~HC+ljCC;}!HK>+HD$(D$ DLHKSDCCH0_^[SWHHHHD$0C;rPCCC;}!HKW+HD$(D$ DL?HKC3HT$0HcHAH;sHD$0HDCCHH_[/pSUVWH(HHH3C~1HSHcHBH;HTHMUȅu C;|ϋC;|3~;DC;}:fHSHcHBH;KHTHMUȅt C;|ϋC;}9HSFD΋ONjHcLBI;HLIcI;HLC;tHKDCD+Ƌ"K+ΉsCCH(_^][PSWH(HHHȅt0HH SF.HHKDKE3{| HH(_[SH HHKDKE3@|H3H [ЕSUVWH(AAHHGuO|}| G;}(C;!HOHDDHH(_^][HG;} 鬦 颦fH(_^][@SVWH AD;ͦEHHzH _^[HH _^[DIEAHIHSUVWATAUHHHl$0I؋HH}PHeHG;v HH q,LMHA<$ILDEQWAH_G;}!HOF .+HD$(D$ LI;uFHO3HD$(t$ DL\HOB.D 6G+HD$(D$ L6>IcH Ҝ ,HHA<$E3HILHW;DH.GAʼnGH;HLLLe-FދHA<$ILLHUDHyA<$ILȅuHMHtH`9LH}PGGHeA]A\_^][ SVWH I؋HH葉HH ǜ*LHHH _^[HH _^[SVWH0IHًC;v SHCHH;u HiC;}!HKDO+HD$(D$ L HKHcHAH;s HtCCCCH0_^[+*@SUVWH(AAHHF;~  >F+;1HNH DDHH(_^][HH(_^][3Б33̰SWH8HHcWH ?)HHOGHD$(D$ E3L33 HH8_[p3pSVWH HHHC~83HSHcHBH;HTHNVȅu3 C;|˰H _^[SH HH )(HHK'H [SUVWH(IAH|}| 3 F+;HNL;HD$pLDNjHD$pIH(_^][HH(_^][̀H8DAHD$ L3mH8`H8IDAHD$ L3>H8@SH HDCE~HK3 CCCH [SUVWH8HHHl$(/'HH3Hu^ HHHP&G~?3HWHcHBH;s2HTHLHP`ȅt G;|3H8_^][&̀SWH(HHHȅt'HH 3&&HH,HH(_[H3H(_[@H8HHH@HD$(D$ E3L38H8SUVWHXHl$0AHHHeHEHt;H6t HOG3HD$(D$ DLHe(_^][̠SUVWATH0EIHًC+Nj$;} HKHD$(t$ ELŋRH0A\_^][PH8HHH@HD$(D$ EL3H8 DHAHPA;}"tA;}AHHH(DAL33ɃH(ЍSUVWH8HHHD$ H C~S3HSHcHBH;+HTHMUȅtHKHAH;HDC;|3HD$ HD$ H8_^][@SUVWATH HHHןH h3#HHC~Y3HSLcHBL;˟JTHNVȅtHSHBL;JTHC;|HH A\_^][̠DAH5L3H̐MDAD+HH̀SUVWH(IAHF;v| F+;~H;}>ffffHVHcHBH; HTHMUȅt ;|θH(_^][SUVWH8HHHD$ HОGX|MfDHWHcHBH;۞HTHMUȅtHOHAH;HD}3HD$ HD$ H8_^][PLDAAPH.H@MDBHH0SUVWATH IALHAD$ut'-;r+G;~5fIT$HcHBH;QHTHMUȅt ;͸H A\_^][̀SVWH HHHC~-3HSHcHBH;+HTHOWC;|H _^[0SH@H3HD$ 3HD$ HD$(HD$0HL$ }LHT$ H9 HH@[HH3HD$ 3HD$ HD$(HD$0HHL$ .HT$ H mHH̰HH3HD$ 3HD$ HD$(HD$0HHL$ ިHT$ H BHHpSUVWH8AH|}| &E+;} CH wH؋HRHMLCHD$(t$ E3ɋsHH8_^][LIIEIHE3HЈSWH(HHHȅu"HH HHODOE3DH(_[̀SVWH DIE;HIE+HH _^[HH _^[PSH HHȅu$H LHHIH [HH [SWH(HHH HHHHkH(_[ЇSWH(HHH HHHHH(_[̐SWH(PHPHH FQHHH;HH(_[PSWH(HHHȅu%HH D` @3 <7 8- 4\ 1'X ''T0&P@'L'H'D'@0'<@8i4XD'0P',9($5 P%P. &r& h&@&`&C~&~ȧ~ا&~@&~P9~`&~Ч&~&~&~x&~X '~('~X%~B~p&~@"~&~&~`&~&~`~8 %~$&~ü~p^&~x~E&~b~ P&~D&~(~|~ԑx~Ȫ&t~&p~h&l~8 &h~d~`~Щ%\~%X~%T~X%P~0%L~%H~D~%@~&&H~`%D~0i@~D&<~@\&8~ &4~&0~&,~D&(~x'<~ '8~8)4~)0~),~H)(~<*<~e)8~+*4~Ȫ_*0~H,~ >(~n$~ ~~@>~)~~g* ~*~*~* ~~h~p3~xS*} L*}r*}l*}b*}@*}B*}Y*}0T*}@ *}]*}P}0N*})}p}y}`*}Y*}8I}=*}د-*}-*}8*}X3*}00*}v*}ɵ}Ȯ*}*}p*}@*} +}*|}ȭx}et}Up}hEl}H5h}(+d})+`}p+\}[+X}в]+T} $T+P}+L}H}+D}+@}i<}`+8}0+4},0}+,} ,(},$}h, }8 ,},}د+}} }p,}p}@} |+|خ+|+|Э+|@+|x+|+|'|+|+||F'|,|,|p:,|@I,|,|e||E|ذ`,|,|,|P<`-|X-|-|-|-|`.|8.| .|.||x|-t|в)p|в*l|-h|o/d|0`|0\| (X|ɰT|x0P|L|0`0H|PZ0D|`x0@|hi<|p08|p324|.20|/,|/(|/$|/ |г/|/|/| 1|01 |@1|H1|P1|`1{pp{1{p1{1{{1{1{{{{ȵ|1{1{ص1{{{i{1{1{x1{81{@{H1{P1{X2{t2{h3{8{ 3{3{3{3{P 3|{ #3x{<3t{3p{p3l{@3h{3d{ع3`{3\{P0X{T{3P{H3L{3H{3D{3@{3<{838{H434{X40{h­,{x4({4${4 {4{ 4{$4{<,5{P5 {дT5{شm5{a5{\5z5z5z 5z(6z86zQ6z8Q6z`Q܊6zx6z6z6z6z6zȵ~7zصw7zn7zp7zu7zp7z(-zW7zhS8z88z8zؼ9z:zxwzH:z:zl:z7;zm;|zXdf;xz(p<zi<zȺ8z?4z ?0z0<{?,z,A(z3$zA zAz*Az9zȽ-)zȽf) zн-AzؽS)za)z\)y@yyȼyм`&yؼZ&y@y@y@y>yȽnyEyyy yhL@y8L@y[@yHRy yyX!@yȾ0@yؾ7@y8y@y@y@y'y>Ey7Eyx4EyH$E|yExy'tyEpylypDhy@Ddy`yD\y0dXyҥTyp¥PyH ELyؿPEHyQEDyWF@yPLFwnww5 w%wwwvHvjv<vhTnv@lHvxvlv vćv܇vHvHv8HvHvHvrvv Av(Av8{HvHHvPHv`#HvHHvIvIv IvIv`Iv0IvvHXvvx@v@|vpIxv~tvZIpv_IlvYhv ĆNIdvJ`v@\v8JXv TvvJPv8zJLvHvpiJDv _J@vOJuIu0uuuu޺u`κu@u !IuiuxYu`IuHGupGu0GuHuHuBu`ٔuxɔu`vHukH|u@xutuX@Hpu0iluhEHhuHHdun`u^\u$HXuHTuHPuHLuXGHu`GDuG@uttFt FtDG tBGtt.Gt$GsDs02Fs8FsssHFsFsFsFsÏs|Fs8sss s s βs~eFs(FsFsuFsXvFs(~̸sdFs^FsVFs ~spKFsDFspQFsIFs9F|s@SxsP.FtsXFps7ls7hs7ds7`s@E\sEXsÍTsEPsELsEHs(ADs@sHEss ?E s=Es3Essrr ~rXDr`r DrPIrXDrxDrrDrDrDrDrxDrsDrcDrSDrCDr(3Dr8#DrHDrXDrhCrxCrCrCrCrzCrt|DrDrDr(Drr rhBr0LDr0ODrxBrX9rp5Drr%r.BrD|rهxrɇtrAprClrAhrdrA`rC\r YXr8~ATrAPrHCLrHHrP Dr@r`z8Cq{Cq()qP[CqKCqDCqPqh+CqH%Cq$CqqyCqqCqCq>qIqn>q)qBqBq(q0qBqq0Bq0qxxBq(Bq3qBqB|qp~=xq9tqxBpqLyBxq>=q|q=xq@tyBtqɂ|q0<xqhtqhyBpq0xqxytqpqNlqChqHUdqB`q\q`-XqX-Tq(CPq0-Lq((-Hq8BDqHB@qPBCot.Co>o)CoCooCo`Bo0BooBoBoPBoHNo>onooNopBoX&o@&oeBoX#o(3o#o%o%ohBo@%|o(#xo8{#tohApox%loK#hoh%dogB`ot%\ohd%Xo"To(D%Po"Lo$%HoDo`@o-n8n(nn>nn>n[@nHpnP`n/@n'@n#@nX@n@n@n @n@n@n?n?n?|nuxn?tn?pn)lnn?hn@dn?`n`?\n?Xn?Tn @Pnx@LnP @Hn(@Dn@@n?n@n`@nH8 np(nXn@q@nXmY@mXW@mM@mj@m`@mV@mL@mH@mM@mmB@md@m@mL@mG@m<@m:@m=m,@m%@m(@m&@m@m@m)@m&@m@m@m@m@m?m?m;|mx?xm`?tmH?pm0?lm?hmB;dm?`m?\m?Xm?TmXHPm@8Lm(kb?Hm?Dm@m@*8m *4m*0m>,mH>(m0>$m> m>m)m)m(m) mp)mXmh>m@)ll>l>l>l B p`P0@@B@20@  bp`P0@%# pP0@ 5 3p`P0@ 53p`P0@  p`P0@ % #p`P0@ 53p`P0@ % #pP0@RpP0@Bp0@2p`0@Rp`0@  2p`P0@Bp`P0@ % #RpP0@  hbp0@ % #pP0@%# bp`P0@b@rp`0@  Bp`P0@bp`P0@ %# p`P0@bp0@ 53 p`P0@ % #pP0@ %#r p`P0@ %# p`P0@ %# p`P0@ % #bp`P0@p0@ %#p`P0@ %# p`P0@p`0@ 53! p`P0@ EC p`P0@ EC p`P0@%# p`P0@%# rp`P0@%# p`P0@ % #P0@ % #rpP0@%# p`P0@ %# p`P0@R p`P0@  Rp`P0@%# Rp`P0@%# p`P0@%# p`P0@ %#R p`P0@%# p`P0@2 p`P0@ %# p`P0@ 53p`P0@ % #P0@ 53 p`P0@p`P0@ % #bp`P0@ % #RP@  p`P0@ % #p`P0@%# bp`P0@%# p`P0@ 53 p`P0@ %#R p`P0@%# p`P0@53 p`P0@ % #rpP0@  p0@  p`0@p`P0@p`P0@  p`P0@  p0@r0@ % #RpP0@p0@ 53 p`P0@p0@ %#p`P0@R0@ % #P0@bP0@  p`P0@%# p`P0@ %# p`P0@ b p`P0@  p`P0@ %# p`P0@ %#! p`P0@ ECp`P0@"@ 53/ p`P0@%# P0@%# p`P0@ 53p`P0@ % #p`P0@ 53 p`P0@  p`P0@ EC p`P0@%#  p`P0@%# pP0@%# p`P0@ 53 p`P0@ % #RP@ p`P0@0@  p`P0@ 53 p`P0@53 p`P0@ % #bP0@  p`0@0@ 53 p`P0@r p`P0@53 p`P0@! !x h  p`P0@0@  p`P0@44.(x h p`P0@xh p0@ 5h3%p`P0@  hp0@%# p`P0@  p0@  (p`P0@p`P0@xh p0@53  p`P0@h rp`P0@  hp`0@  hR0@ %# p`P0@  p`P0@ 53 p`P0@53 p`P0@ 5 3rpP0@ 53 p`P0@ %# p`P0@,,#xh# p`P0@  p`P0@ 537 p`P0@&5&xh3A p`P0@ h p`P0@ %h #p`P0@ h p`P0@h p`P0@p`0@%# p`P0@%# p`P0@%# p`P0@%# >p`P0@@0@  hrp`0@h Rp`P0@ h p`P0@%h #P0@  hr0@  h0@@ %# p`P0@%# p`P0@ x h p`P0@%# p`P0@%h #rP@0@53 p`P0@  "p`0@  5p`P0@ % #rP@ % #P0@ 53 p`P0@  (p`0@  p`P0@%# Rp`P0@53 p`P0@ 5 3p`P0@ %#r p`P0@8X:B:B@:Bp:B@:BH:BP:B:B(@p:B:B`&:B0:B:B:B:B:B:B:B:B:B:B:B:B:B9:B::B::B:Bሎ:B9:B:B:Bp&:B(:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:B:B:B:Bq:B:B:B&:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:Bؖ:B:B:Bq:B:B:B2:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:B:B:B:Bq:B:B:BK:Bh:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:B8:B:B:Bq:B(@p:B:BxM:B(:B:B:B:B:B:B:B:B:B:B:B:B:BH<:BX<:Bh<:BP:Bሎ:B9:B@:Bp:B@:B:BN:B[:Bx:B8:Bؚ:B:Bn:B蚩:B@:B:BN:BS:B:B0:BP:B):Bш:Bo:Bp:B@:B:BN:BS:Bx:B0:B؛:B):Bш:B:B:B@:B:BN:BӉ:B:B:B:B:B:B:B:B:BQ:B:B؉:B:BN:B :B:B:B:B:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:BH:B(:Bp`HH؝:Bሎ:Bو:Bɇ:B:B:B:B@:B:BN:BK:B :B:B:B:BO:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:Bx:B:B:Bq:BXz:B:B@:B:BO:BӉ:B:B:B:B:B:B:B0:BR:Br:B:Bi:B`:B@:B:B(O:BS:Bh:B0:BȠ:B):Bш:BH:B蠩:B@:B:B8O:BK:B:B:B鮎:BH:B@:B:BHO:BS:BP:B0:B:B):Bш:BhO:BXW$$@:B:BXO:B+:BС:B:B:B:B:B0:Bp:Bx:BP:B:BX:B:B:B:Bh:BP:B:B:B:B`:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B`:B:BQ:B1:B:B1:Bɇ:B9:BA:Bn:Bࣩ:B@:B:BP:B:B裩:B0:Bo:B@:B@:B:BP:B:BH:B0:B(@p:B:B8P:B:B:B:B:B:B:B:B:B:B:B:B:B:B0=:B@=:BP=:B:Bሎ:B9:B(@p:B:BHP:B:B:B:B:B:B:B:B:B:B:B:B:B:Bp=:B=:B=:B:Bሎ:B9:B荫:B:B@:B:B(P:BC:B:B:B:Bܩ:B:B@:B:BXP:B[:B :B8:B:B:B!:B:B@:B:BhP:B:B:B(:B:B:B(@p:B:BP:B:B:B:B:B:B:B:B:B:B:B:B:B:B=:B=:B=:B:Bሎ:B9:B:B:BP:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:B:B:B:Bq:B:B:BP:BH:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:B@:B:B:Bq:B:Bp:B@:B:BxP:BÉ:Bx:B8:B@:BH:BP:BX:B`:Bh:B:B:B:B:B(:B@:B:BP:B:B0:B(:B:B:B:B:BP:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:B:B:B:Bq:BXz:BЭ:B@:B:BP:BS:Bح:B0:B8:B):Bш:BA:Bi:BX:B X:B:BP:B{:Bh:B:BH:BP:B:BQ:B U@:B:BP:Bs:B:B:B:B:B:B:B:Bũ:B(Q:B W""@:B:BQ:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B :B膏:B :B:B:B:Bو:Bɇ:BA:Bi:B:B@:B:BQ:B:B:B :B(:B0:B8:B@:BH:BP:BX:B(:BṎ:B鹎:B:Bn:BX:B@:B:BQ:BӉ:B`:B:B:B:B:B:B಩:Bs:B}:B:B!:B:B(W X:B:BQ:Bc:B:B@:BH:BP:B:BX:B`:Bh:Bp:Bx:Bг:BpZ:B):Bш:Bo:B:B@:B:BQ:BӉ:B:B:B:B:B:B:B:B(f:B~:B:Bn:B:B@:B:BQ:BӉ:B:B:B:B:B:B:B@:B;:B{:B:B:B:BQ:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:Bp:B:B:Bq:B:B:BR:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:B:B:B:Bq:B:Bз:B(@p:B:BR:B:Bط:B:B:B:B:B:B:B:B:B:B:B:B:B >:B>:B>:B0ظ:Bሎ:B9:B_:B:B@:B:B R:B:B:B(:B`:B:BA:By:Bp:B(W X:B:B0R:Bۉ:B:B@:BH:BP:B:B:B:B:B:B:B8:B:B):Bш:Bܩ:Bh:B@:B:B@R:BÉ:Bp:B8:B@:BH:BP:BX:B`:Bh:B:B(:B:B`R:B U @:B:BPR:B:B :B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:Bh:B:Bݩ:B:Bو:Bɇ:B(:B- R:B(E@:B:BR:B#:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B8:B:Bp:Bx:B :B(:B0:B8:B@:BH:BP:BX:B`:B:Bh:B:B:B:B8:B:BR:Br:B:Bو:Bɇ:B_:Bྩ:B@:B:B8S:BK:B辩:B:Bᰎ:B@:B@:B:BHS:B:BH:B:B:B:B:B:B:B :Bؿ:B麎:B:BhS:B W @:B:BXS:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:Bp:B`:BP:B:B ܩ:B:Bو:Bɇ:B:B:BS:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:B©:B:B:Bq:B؉:B:BS:BH:B:B:B:B:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:BH:B(:BHz8z z z(ĩ:Bሎ:Bو:Bɇ:B:B荫:Bhĩ:B@:B:BS:BS:Bpĩ:B0:Bĩ:B):Bш:B荫:Bĩ:B@:B:BS:B:Bĩ:B0:Bo:BPũ:B(@p:B:BS:B{:BXũ:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:BPƩ:Bሎ:B9:BA:Bi:BpƩ:B@:B:BT:B:BƩ:B :B(:B0:B8:B@:BH:BP:BX:Bǩ:B:B:B:BA:B:BHǩ:B(X:B:BT:Bs:BXǩ:B@:BH:BP:B:BA:B@:Bǩ:B(X:B:B T:Bs:Bǩ:B@:BH:BP:B:B:Bxȩ:B@:B:B0T:B[:Bȩ:B8:Bȩ:B:Bn:Bȩ:B@:B:B@T:BC:Bȩ:B:B:B!:BXɩ:B@:B:BPT:BK:B`ɩ:B:B):Bɩ:B@:B:B`T:B:Bɩ:B:B:B:B:B:B:B :BPʩ:B:B:Bʩ:B- T:B(E@:B:BpT:B#:Bʩ:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B8:B:Bp:Bx:B :B(:B0:B8:B@:BH:BP:BX:B`:B:Bh:B:B˩:Bpʩ:B :B:B(f:B~:B:Bو:Bɇ:BA:B@:BX̩:B@:B:BU:B:Bh̩:B :B(:B0:B8:B@:BH:BP:BX:Bͩ:B:B:B:B؉:B:BU:B:B:B:B:B:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:BH:B(:B@p0pppXΩ:Bሎ:Bو:Bɇ:B:Bo:BΩ:B@:B:B U:BC:BΩ:B:B:BPЫ:Bϩ:B@:B:B0U:B:Bϩ:B:B:B:B:B:B:B :Bϩ:Bh:B:Bϩ:B- PU:B(E@:B:B@U:B#:Bϩ:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B8:B:Bp:Bx:B :B(:B0:B8:B@:BH:BP:BX:B`:B:Bh:B:B@ѩ:Bϩ:B :Bh:Bs:B}:B:Bو:Bɇ:B؉:B:BU:B:B:B:B:B:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:BH:B(:Bkkkkҩ:Bሎ:Bو:Bɇ:B:B@:Bө:B@:B:BU:BC:Bө:B:B:BA:B:Bpө:B@:B:BU:B:Bө:B :B(:B0:B8:B@:BH:BP:BX:Bԩ:B8:B0n:B:B:BHԩ:B@:B:BV:BC:BPԩ:B:B:BA:By:Bԩ:B X:B:BV:B{:Bԩ:B:BH:BP:B:Bxթ:B- 0V:B(E@:B:B V:B#:BXթ:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B8:B:Bp:Bx:B :B(:B0:B8:B@:BH:BP:BX:B`:B:Bh:B:B֩:BHթ:B ؇:Bȴ:B;:B{:B:Bو:Bɇ:BV:B W""@:B:BV:B:B0ש:B:B:B:B:B:B:B:B:B:B:B:B:B :B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:Bة:B:B`H:Bϩ:Bh:B:Bو:Bɇ:B!:B٩:B@:B:B8W:BӉ:B ٩:B:B:B:B:B:B٩:B :B:B:B :B٩:B@:B:BHW:BÉ:B٩:B8:B@:BH:BP:BX:B`:Bh:Bhک:B:B:B:Bک:B(W X:B:BXW:Bc:Bک:B@:BH:BP:B:BX:B`:Bh:Bp:Bx:BH۩:BY:B):Bш:BA:Bn:Bx۩:B(X:B:BhW:Bs:B۩:B@:BH:BP:B:B:Bܩ:B@:B:BxW:B:Bܩ:B(:Bxܩ:B:BA:Bn:Bܩ:B X:B:BW:B{:Bܩ:B:BH:BP:B:B:B ݩ:B@:B:BW:BӉ:B(ݩ:B:B:B:B:B:Bݩ:Ba:Bi:B:BH:Bݩ:B@:B:BW:B:Bݩ:B(:B@ީ:B:B):B:B:BW:BH:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BXߩ:B:B:Bq:BPީ:B(@p:B:BW:Bˉ:Bߩ:B:B:B:B:B:B:B:B:B:B:B:B:Bp:Bx:B:B:Bሎ:B9:BW:BXW$$@:B:BW:B+:B:B:B:B:B:B0:Bp:Bx:BP:B:BX:B:B:B:Bh:BP:B:B:B:B`:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B:By:B:B:B1:Bɇ:B9:BA:BA:Bn:B:B@:B:BX:B:B:B :B(:B0:B8:B@:BH:BP:BX:BX:Bx:B(:B:BX:BW@:B:BX:B:B:B:B:B:B:B:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:Bx:BẎ:B麎:B:Bɇ:Bn:B:B@:B:BX:BC:B:B:B:By:B :B@:B:BX:BS:B(:B0:B:B):Bш:BH:B:B(U X:B:BX:Bc:B:B@:BH:BP:B:BX:B`:Bh:Bp:Bx:Bh:B5:B):Bш:B:B:B@:B:BX:BS:B:B0:B:B):Bш:BY:BXW$$@:B:BY:B+:B :B:B:B:B:B0:Bp:Bx:BP:B:BX:B:B:B:Bh:BP:B:B:B:B`:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B:Bٺ:B):B!:B:B1:Bɇ:B9:BA:B:B0:B(W X:B:BY:Bc:B8:B@:BH:BP:B:BX:B`:Bh:Bp:Bx:B:B7:B):Bш:BY:BXW$$@:B:BY:B+:B :B:B:B:B:B0:Bp:Bx:BP:B:BX:B:B:B:Bh:BP:B:B:B:B`:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B:BѺ:B:B:B:B1:Bɇ:B9:BA:BZ:BXW$$@:B:BxZ:B+:B0:B:B:B:B:B0:Bp:Bx:BP:B:BX:B:B:B:Bh:BP:B:B:B:B`:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B:Bɺ:B:B:B:B1:Bɇ:B9:BA:B9:B@:B@:B:B([:B[:BH:B8:B:B:B@:B:B@:B:B8[:BÉ:B:B8:B@:BH:BP:BX:B`:Bh:BP:B:B:Bٯ:Bp:B@:B:BH[:B:Bx:B:B:B:B:B:B:B :B:B:B:B :B(:B@:B:BX[:BÉ:B0:B8:B@:BH:BP:BX:B`:Bh:B:B0n:B:Bx[:BW@:B:Bh[:B:B:B:B:B:B:B:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:Bɇ:Bn:B:B@:B:B[:BK:B:B:B:Bp:B(W X:B:B[:Bc:Bx:B@:BH:BP:B:BX:B`:Bh:Bp:Bx:B0:Bi:B):Bш:B:B- [:B(G@:B:B[:B#:Bp:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B8:B:Bp:Bx:B :B(:B0:B8:B@:BH:BP:BX:B`:B:Bh:B:B:B`:B(:B(٩:B :B:B:Bو:Bɇ:BI:B鮎:BH:B X:B:BH\:B{:BX:B:BH:BP:B:B:B- x\:B(G@:B:BX\:B#:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B8:B:Bp:Bx:B :B(:B0:B8:B@:BH:BP:BX:B`:B:Bh:B:Bh:B:B P:BY:Ba:Bi:B:Bو:Bɇ:B:B:B@:B:B\:BS:B:B0:B0:B):Bш:Bo:BP:B@:B:B]:BK:BX:B:BA:Bᰎ:B:B(W X:B:B]:Bۉ:B:B@:BH:BP:B:B:B:B:B:B:Bx:B:B):Bш:B8]:BU@:B:B(]:B[:B:B:B:B:B:B :B:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:Bɇ:Bn:B:B@:B:BX]:BK:B:B:Bx]:BU@:B:Bh]:B[:B8:B:B:B:B:B :B:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B(:B:B:B:Bɇ:B:Bh:B@:B:B]:BK:Bp:B:BA:Bn:Bܩ:B:B 8U X:B:B]:B3:B:B@:BH:BP:B:B:B:B:B:B:B:B:B:B:B:B):Bш:B9:B:B ]:BG @:B:B]:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B/:Bٯ:B:B@:B:B]:B:B:B(:BP:B:B:B`:B@:B:B]:BS:Bh:B0:B:B):Bш:B@:B:B@:B:B^:BK:B:B:BA:B:BH:B X:B:B^:B{:BX:B:BH:BP:B:B!:B:B@:B:B(^:BC:B:B:B:B`:B H^:BE @:B:B8^:B:BX:B:B:B:B:B:B:B:B:B:B:B:BH:B:B(4:BA:Bi:B0:B X:B:Bh^:B{:B@:B:BH:BP:B:B):B:B@:B:Bx^:B[:B:B8:B0:B:B:B@:B@:B:B^:BӉ:BH:B:B:B:B:B:B:B:B ܩ:B:B^:BU@:B:B^:B[:B:B:B:B:B:B :B:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:Bɇ:B:B(:B(W X:B:B^:Bc:B0:B@:BH:BP:B:BX:B`:Bh:Bp:Bx:B:BQ:B):Bш:B:B:B@:B:B^:BÉ:B :B8:B@:BH:BP:BX:B`:Bh:B:B鹎:B:Bᰎ:B:B@:B:B^:BS:B:B0:B8:B):Bш:BH:BX:B@:B:B^:BӉ:B`:B:B:B:B:B:B:B:Bݩ:B:BA:B@:B:B X:B:B_:B{:B :B:BH:BP:B:B:B- 8_:B(G@:B:B_:B#:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B8:B:Bp:Bx:B :B(:B0:B8:B@:BH:BP:BX:B`:B:Bh:B:B0 :B:Bx:B:B:BQ:B:Bو:Bɇ:B_:BX:B:B_:B:B :B@:BH:BP:B:BA:B:B :B@:B:B_:B:B( :B :B(:B0:B8:B@:BH:BP:BX:B :By:B:B:BA:B:B :B X:B:B_:B{:B :B:BH:BP:B:B_:B :B@:B:B`:BC:B :B:B:BP:B- :B:B0`:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:B:B:B:Bq:B@`:B(G@:B:B`:B#:B0:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B8:B:Bp:Bx:B :B(:B0:B8:B@:BH:BP:BX:B`:B:Bh:B:B:B :B :Ba:Bi:Bq:B:Bو:Bɇ:B`:BXW$$@:B:B`:B+:B:B:B:B:B:B0:Bp:Bx:BP:B:BX:B:B:B:Bh:BP:B:B:B:B`:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B:BY:Bɹ:Bq:B:B1:Bɇ:B9:BA:Bᰎ:B:B@:B:Bpa:B:B :B(:B:B:B:B:B@:B:Ba:B[:B:B8:B:B:B:B:B@:B:Ba:B:B:B:B:B:B:B:B:B :B:B ܩ:B:BH:B:B@:B:Ba:B:B:B:B:B:B:B:B:B :BX:Bݩ:B:B:B a:BE @:B:Ba:B:B:B:B:B:B:B:B:B:B:B:B:B@:Bx:B:B :BA:B:B`:B X:B:Ba:B{:Bp:B:BH:BP:B:Bٯ:B:B@:B:Ba:BS:B:B0:B`:B):Bш:B:B:B(@p:B:Bb:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B>:B>:B>:B8':Bሎ:B9:BA:B:B:B@:B:Bb:B:B:B :B(:B0:B8:B@:BH:BP:BX:BP:BQ:B1:B:BA:B:B:BB:B:BU@:B:B b:B:B:B:B:B:B:B:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:Bh:B:B:Bɇ:Bܩ:B:B@:B:B0b:B#:B:B:B8:B):Bш:BPЫ:BX:B@:B:B@b:B:B`:B(:B:B:B`b:B U""@:B:BPb:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:BX:BȈ:B:BR:Br:B:Bو:Bɇ:Bb:BU@:B:Bb:B:B:B:B:B:B:B:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B0:B:Bɇ:By:B:B@:B:Bc:B[:B:B8:BP:B:B):B`:B@:B:Bc:B:Bh:B(:B:B:B:B- 8c:B(G@:B:B(c:B#:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B8:B:Bp:Bx:B :B(:B0:B8:B@:BH:BP:BX:B`:B:Bh:B:B` :B:B:BP:B:B ܩ:B:Bو:Bɇ:B!:B :B@:B:Bc:B:B :B:B:B:B:B:B:B :BX!:B:B:B!:B- c:B(G@:B:Bc:B#:B!:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B8:B:Bp:Bx:B :B(:B0:B8:B@:BH:BP:BX:B`:B:Bh:B:B#:Bx!:B:B9:BA:BI:B:Bو:Bɇ:B#:B- xd:B(E@:B:Bhd:B#:Bp#:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B8:B:Bp:Bx:B :B(:B0:B8:B@:BH:BP:BX:B`:B:Bh:B:B$:B`#:B@:Bh:B:Bݩ:B:Bو:Bɇ:Be:BXW$$@:B:Bd:B+:BH%:B:B:B:B:B0:Bp:Bx:BP:B:BX:B:B:B:Bh:BP:B:B:B:B`:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B&:B1:B!:B:B:B1:Bɇ:B9:BA:BA:B:B :BX':B 8U X:B:Be:B3:Bp':B@:BH:BP:B:B:B:B:B:B:B:B:B:BP(:B01:B):Bш:B9:Be:B U @:B:Be:B:B(:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B*:Bh:B`:B`|:Bx=:B:Bو:Bɇ:BA:B@:B@:Bh*:B 8U X:B:Bf:B3:B*:B@:BH:BP:B:B:B:B:B:B:B:B:B:B`+:Bp2:B):Bш:B9:B_:B+:B(U X:B:B f:BS:B+:B@:BH:BP:B:B:B :B(:B0:B8:B`,:BJ:B):Bш:B:B,:B@:B:B0f:B:B,:B:B:B:B:B:B:B :B(-:Bi:B:BI:B鮎:BH-:B@:B:B@f:B:BX-:B :B(:B0:B8:B@:BH:BP:BX:B-:B):B!:B:B8.:B `f:BG @:B:BPf:B:B0.:B:B:B:B:B:B:B:B:B:B:B.:B .:B:B:B :B/:B@:B:Bf:B[:B/:B8:Bp/:B:B:B/:B@:B:Bf:BC:B/:B:B:B荫:B/:B@:B:Bf:BK:B/:B:BA:B:BH0:B@:B:Bf:B:BX0:B :B(:B0:B8:B@:BH:BP:BX:B0:B!:B:B:B :B 1:B@:B:Bf:B#:B(1:B:B1:B):Bш:Bٯ:B1:B@:B:Bf:BӉ:B1:B:B:B:B:B:B02:B:B:B:B@:B`2:B@:B:Bf:B#:Bh2:B:B2:B):Bш:B:B2:B@:B:Bf:B[:B2:B8:BP3:B:B :B`3:B@:B:Bg:BÉ:Bh3:B8:B@:BH:BP:BX:B`:Bh:B3:B:B:BH:B4:B@:B:Bg:BC:B 4:B:B:B:B4:B(W X:B:B g:Bc:B4:B@:BH:BP:B:BX:B`:Bh:Bp:Bx:B@5:B:B):Bш:BH:Bp5:B@:B:B0g:BS:Bx5:B0:B5:B):Bш:B:B5:B@:B:B@g:BÉ:B6:B8:B@:BH:BP:BX:B`:Bh:B6:B:B:BA:B:B6:B(W X:B:BPg:Bۉ:B6:B@:BH:BP:B:B:B:B:B:B:Bx7:Bq:B):Bш:B:B7:B@:B:B`g:BS:B7:B0:B8:B):Bш:Bg:B U@:B:Bpg:Bs:B08:B:B:B:B:B:B8:BA:Bg:BXW$$@:B:Bg:B+:B8:B:B:B:B:B0:Bp:Bx:BP:B:BX:B:B:B:Bh:BP:B:B:B:B`:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:Bh::Bٹ:BṎ:B鹎:B:B1:Bɇ:B9:BA:BPh:B W@:B:B@h:Bs:B::B:B:B:B:B:B;:BhG:Bn:B;:B@:B:B`h:B:B;:B:B:B:B:B:B:B :B(<:B{:B:Bh:B 8W X:B:Bph:B3:BH<:B@:BH:BP:B:B:B:B:B:B:B:B:B:B(=:Bѹ:B):Bш:B9:B荫:Bh=:B@:B:Bh:B:Bp=:B(:B=:B:BA:Bѯ:B=:B@:B:Bh:B:B=:B :B(:B0:B8:B@:BH:BP:BX:B>:Bɹ:Bq:B:BA:B:B>:B X:B:Bh:B{:B>:B:BH:BP:B:Bh?:B h:BE @:B:Bh:B:B`?:B:B:B:B:B:B:B:B:B:B:B@:BP?:B:B:B:B8@:B@:B:Bh:BÉ:B@@:B8:B@:BH:BP:BX:B`:Bh:B@:B:B:B:B@:B@:B:Bi:B:B@:B6:B6:B6:B6:B6:BA:B:B:B :B:BH:BA:B@:B:Bi:B:BA:B0:B:B:B8i:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BC:B:B:Bq:BHi:B W@:B:B(i:Bs:B@C:B:B:B:B:B:BC:B@S:B):BC:B@:B:BXi:BӉ:BC:B:B:B:B:B:BpD:B:B:B:BA:Bn:B[:Bƒ:BD:BU@:B:Bhi:B:BD:B:B:B:B:B:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:BE:B;:B{:B:Bɇ:By:BE:B@:B:Bxi:B:BE:B(:BXF:B:B荫:BhF:B(U X:B:Bi:Bc:BpF:B@:BH:BP:B:BX:B`:Bh:Bp:Bx:B(G:Bxĩ:B):Bш:B:BXG:B@:B:Bi:B:B`G:B0:BA:B:BG:B X:B:Bi:B{:BG:B:BH:BP:B:BPЫ:BPH:B@:B:Bi:BӉ:BXH:B:B:B:B:B:BH:Bϩ:Bh:B:Bi:B U @:B:Bi:B:BI:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:BJ:B:Bh:Bs:B}:B:Bو:Bɇ:B_:BJ:B@:B:B j:BS:BJ:B0:BHK:B):Bш:B@j:B U @:B:B0j:B:BhK:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:BL:BЉ:B:B(f:B~:B:Bو:Bɇ:B:B@M:B@:B:Bj:B#:BHM:B:BM:B):Bш:Bj:BW@:B:Bj:B:BM:B:B:B:B:B:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:BN:B:B:B:Bɇ:BO:B j:BE @:B:Bj:B:BO:B:B:B:B:B:B:B:B:B:B:BO:BN:B:BXԩ:BO:B k:BE @:B:Bj:B:BO:B:B:B:B:B:B:B:B:B:B:BP:BO:B:Bө:BA:B:BP:B@:B:B(k:B:BP:B :B(:B0:B8:B@:BH:BP:BX:BpQ:B:B:B:BA:Bᰎ:BQ:B@:B:B8k:B:BQ:B :B(:B0:B8:B@:BH:BP:BX:BHR:B:B:B:BXz:BxR:B@:B:BHk:B:BR:B:B:B:B:B:B:B :BS:Br:B:B!:B0S:B@:B:BXk:B:B8S:B0:B:BS:B@:B:Bhk:BS:BS:B0:BS:B):Bш:B0T:B k:BE @:B:Bxk:B:B(T:B:B:B:B:B:B:B:B:B:B:BT:BT:B:Bɩ:By:BU:B@:B:Bk:BÉ:BU:B8:B@:BH:BP:BX:B`:Bh:BU:Bq:B:BU:Bk:B0E @:B:Bk:B :BU:B:B:B:B:B:B:B:B:B:B:BV:BU:B:B:B:Bɇ:BV:B l:BE @:B:Bl:B:BV:B:B:B:B:B:B:B:B:B:B:BW:BV:B:BΩ:BA:B:BW:B X:B:B0l:B{:BW:B:BH:BP:B:BPl:BXU$$@:B:B@l:B+:BPX:B:B:B:B:B0:Bp:Bx:BP:B:BX:B:B:B:Bh:BP:B:B:B:B`:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:BY:B:Bx:B(:B:B1:Bɇ:B9:BA:B!:B`Z:B@:B:Bl:BS:BhZ:B0:BZ:B):Bш:BA:Bᰎ:BZ:B X:B:Bm:B{:BZ:B:BH:BP:B:BA:Bn:B[:B(U X:B:Bm:Bۉ:B[:B@:BH:BP:B:B:B:B:B:B:BH\:B}:B):Bш:B0m:B W""@:B:B m:B:Bx\:B:B:B:B:B:B:B:B:B:B:B:B:B :B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B^:B :BY:Ba:Bi:B:Bو:Bɇ:Bm:B U""@:B:Bm:B:B`^:B:B:B:B:B:B:B:B:B:B:B:B:B :B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B_:BH:B:B:B:B:Bو:Bɇ:B؉:B:B0n:B:B:B:B:B:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:BH:B(:Bpa:Bሎ:Bو:Bɇ:B:BPn:B U @:B:B@n:B:Ba:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B(c:Bp:Bȴ:B;:B{:B:Bو:Bɇ:Bn:B U@:B:Bn:Bs:Bc:B:B:B:B:B:B d:B:B`d:B- n:B(G@:B:Bn:B#:B@d:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B8:B:Bp:Bx:B :B(:B0:B8:B@:BH:BP:BX:B`:B:Bh:B:Be:B0d:B:B`H:Bϩ:Bh:B:Bو:Bɇ:Bo:Bf:B@:B:BHo:B:B f:B:B:B:B:B:B:B :Bf:B~:B:BXz:Bf:B@:B:Bho:BH:B:B:B:B:B0X:B:Bxo:B:B@:BH:BP:B:B(E@:B:Bp:B#:Bpi:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B8:B:Bp:Bx:B :B(:B0:B8:B@:BH:BP:BX:B`:B:Bh:B:Bi:Bxi:B:B`:B`|:Bx=:B:Bو:Bɇ:Bo:Bg:B- XU$$@:B:Bp:B+:Bk:B:B:B:B:B0:Bp:Bx:BP:B:BX:B:B:B:Bh:BP:B:B:B:B`:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:Bk:Bө:B8:B0n:B:B1:Bɇ:B9:BA:Bp:B@:B:Bp:BS:Bl:B0:Bk:B):Bш:Bl:B:BXU$$@:B:Bxq:B+:B(n:B:B:B:B:B0:Bp:Bx:BP:B:BX:B:B:B:Bh:BP:B:B:B:B`:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:Bm:Bp̩:B:B:B:B1:Bɇ:B9:BA:Bp:B@:B:Bq:B[:Bn:B8:Bn:B:Bn:B :B(U X:B:Bq:Bc:Bo:B@:BH:BP:B:BX:B`:Bh:Bp:Bx:BXo:B}:B):Bш:Bo:Bn:B U@:B:Bq:Bs:B8p:B:B:B:B:B:B(p:B:Bq:B X:B:Bq:B{:Bp:B:BH:BP:B:Bp:BA:Bѯ:B U@:B:Bq:Bs:Bxq:B:B:B:B:B:Bhq:BP:Bq:B(@p:B:Bq:B:Br:B:B:B:B:B:B:B:B:B:B:B:B:B?:B ?:B0?:Bxr:Bሎ:B9:Br:B:B@:B:BXo:B:Bf:B(:Bs:B:B:Bs:B@:B:Br:B:Bs:B:B:B:B:B:B:B :Bs:BQ:B:Bn:Bs:B@:B:Br:B:Bs:B:B:B:B:B:B:B :B`t:B}:B:BE @:B:BHr:B:BPu:B:B:B:B:B:B:B:B:B:B:B0u:BXu:B:B:B(r:Bt:B  W @:B:Br:B:B8w:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:Bv:B芏:B(٩:B :B:B:Bو:Bɇ:BXr:B(U X:B:Br:Bc:B x:B@:BH:BP:B:BX:B`:Bh:Bp:Bx:Bw:B:B):Bш:B(x:Bo:B(U X:B:Br:Bc:By:B@:BH:BP:B:BX:B`:Bh:Bp:Bx:Bx:B:B):Bш:By:Bn:BXW$$@:B:Bps:B+:B({:B:B:B:B:B0:Bp:Bx:BP:B:BX:B:B:B:Bh:BP:B:B:B:B`:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:Bz:B鸎:B:B:B:B1:Bɇ:B9:BA:Br:B@:B:Bs:B:B{:B:B:B:B:B:B:B :B{:B:B:B{:By:B@:B:Bs:B:BP|:B(:B@|:B:BX|:Bn:B@:B:Bs:B:B}:B:B:B:B:B:B:B :B|:Bx=:B:B}:B荫:B@:B:Bs:BS:B}:B0:Bp}:B):Bш:B}:Bn:B@:B:Bs:B:B~:B(:B}:B:B~:Bn:B@:B:Bs:B:B~:B(:Bp~:B:B~:Bo:B@:B:Bs:B[:B~:B8:B~:B:B:B :B(W X:B:Bs:Bc:B:B@:BH:BP:B:BX:B`:Bh:Bp:Bx:B:B:B):Bш:B:B:B@:B:Bt:B:BH:B0:BP:Bn:B@:B:Bt:BÉ:B:B8:B@:BH:BP:BX:B`:Bh:B:B!:B:B:B):B(@p:B:B t:Bˉ:B :B:B:B:B:B:B:B:B:B:B:B:B:Bp:Bx:B:B:Bሎ:B9:B(:B:B@:B:B0t:B:B:B(:B:B:B:B@:B@:B:B@t:BÉ:BP:B8:B@:BH:BP:BX:B`:Bh:B0:B1:B:BX:B9:B@:B:BPt:BӉ:B:B:B:B:B:B:B؃:B`|:Bx=:B:B:B荫:B@:B:B`t:B:B:B(:Bp:B:B:B:B(U X:B:Bpt:Bۉ:Bp:B@:BH:BP:B:B:B:B:B:B:B@:Bk:B):Bш:Bx:BA:B:B@:B:Bt:B:B:B(:B:B:B:B:BH8W++Pש:B:B0u:BC:BX:B:B:B:B:B:B:B:B:B:B:B:B:B :B:B:B:B(:B0:B8:B@:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B؇:B:B`H:Bϩ:Bh:B:Bو:Bɇ:BI:Ba:BV:Bt:B@:B:B@u:B:B:B:B:B:B:B:B:B :B:B:B:B:B:B@:B:BPu:B[:B:B8:Bx:B:B:B:B@:B:B`u:B:B@:B:B:B:B:B:B:B :B :B0:B:BH:B@:B X:B:Bpu:B{:BЊ:B:BH:BP:B:B؊:BA:BA:B X:B:Bu:B{:Bh:B:BH:BP:B:Bp:BA:B:B؉:B:Bt:B:B:B:B:B:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:BH:B(:Bز:Bሎ:Bو:Bɇ:B:B@:B:Bu:Bp:B:B:B:B:BبW@:B:Bu:B:B:B:B:B:B:B@:B(@:BxЍ:B:B@`8  &:B:Bu:B:B蒪:B:B:B:B:BX:B`:Bh:B:B:B:B:B:B:B:B@:BB:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B@:B:B:B:B:B@:BA:B@:BA:B  аhر8ȱhHȯЯد (0@HPX`hpxȰаذ0Ȱаذ:B8:B):B :Bɇ:B:B:B8@W@:B:Bu:Bh:B:B:B:B:B:BC:Bx:B:B @@@:B:Bu:B :B:B:B:B:Bȯ@:B:Bu:B :B:B:B:B:Bp#0W @:B:Bu:B` :Bx:B:B:B:B:B8E:BXE:BHE:B0E:BH(:B:B @W@:B:Bv:B :B8:B:B:B:B:BxE:B:B1:BH@:B:Bv:B :B:B:B:B:BkjcW@:B:B(v:BX :BP:B:B:B:B:BG:BG:BPؖ:B:B(U@:B:B8v:B :B薪:B:B:B:B:B0G:B@G:BPG:B`G:B:BXz:Bgdi32.dllCallWindowProcSetWindowLongGetCaptureuser32EnumChildWindowsuser32.DllSetCursorPosDeleteObjectGetCursorPosGetWindowRectPostMessageSendMessageDestroyWindowGetParent@:B:BHv:B :B:B:B:B:B(:B:BXv:BP:B:B:B:B:BH:BH:Bp`@:B:Bhv:B:B:B:B:B:BP@:B:Bxv:B:B:B:B:B:B@:B:Bv:BH:B:B:B:B:B  H:B:Bv:B:B:B:B:B:B(H:B:Bv:B:B:B:B:B:B:B:B@:B:Bv:B@:B:B:B:B:B(@:B:Bv:B:B:B:B:B:B8`:B:Bv:B:B:B :B(:B:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B@:B:Bv:B8:B:B:B:B:B@:B:Bv:B:B:B:B:B:B/8@:B:Bw:B:B:B:B:B:B@:B:Bw:B0:B:B:B:B:BFreeLibraryExtractIconExLoadLibrarykernel32.dllDestroyIconExtractIconShell32.dlluser32.dllLoadString @:B:B(w:B:B:B:B:B:B@:B:B8w:B:B:B:B:B:BD@:B:BHw:B(:B:B:B:B:B X%$ :B:BXw:B:Bhw:B:B:B:B:B0:Bp:Bx:BP:B:BX:B:B:B:Bh:BP:B:B:B:B`:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B(:Bٹ:BṎ:B鹎:B:B1:Bɇ:B9:BA:B0U@:B:Bpw:Bx:B:B:B:B:B:BN:B:B):B @@:B:Bw:B :B:B:B:B:B8N:BHN:B @:B:Bw:B:B:B:B:B:Bx0:B:Bw:Bp:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:Bሎ:B!:Ba:B):B `:B:Bw:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B`:Bሎ:B!:Ba:B):B@:B:Bw:B:B:B:B:B:BwLbfx0ȱ:B:Bw:Bh:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:BN:BN:BN:BN:B`:Bሎ:B!:Ba:B):B:BLbfh@ȱ:B:Bw:B:B:B:BO:BO:B:B:B:B:B:B:B:B:B0O:B:B@O:B:B:B:B:B:B:B:B:BO:BO:BPO:B`O:BX:Bሎ:B!:Ba:B):B:BW@:B:Bw:B:BH:B:B:B:B:BO:BP:BO:BP:BO:BO:BO:BO:BP:B P:B8:B:Bxhp p p3 @:B:Bx:B`:B:B:B:B:Bh`@H@0 PO :B:Bx:B :Bظ:B:B :B(:B:B0:B:B:B:BP:B:B:B:B:B:B:Bh:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:Bp:B:Bx:B:B:B:Bp :B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B :B:B:B :B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :B :B :B:B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :BP:BX:B:B:B:B:B :B :B :B:B :B :B :B :B :B :B0 :B8 :B@ :BH :BP :BX :B` :Bh :B:B:B :B :B :B :B :B :B :B:B :B :B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:BXP:BhP:B(H:BA:BI:BQ:BY:B:Ba:Bi:B:B:Bxxh`@H@0 PO :B:B x:B :Bส:B:B :B(:B:B0:B:B:B:BP:B:B:B:B:B:B:Bh:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:Bp:B:Bx:B:B:B:Bp :B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B :B:B:B :B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :B :B :B:B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :BP:BX:B:B:B:B:B :B :B :B:B :B :B :B :B :B :B0 :B8 :B@ :BH :BP :BX :B` :Bh :B:B:B :B :B :B :B :B :B :B:B :B :B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:BP:BP:B8XĪ:BA:BI:BQ:BY:B:Ba:Bi:B:B:B(@:B:B0x:BX!:B:B:B:B:B@(@p:B:B@x:B":B:B:B:B:B:B:B:B:B:B:B:B:BP:BP:BP:BPƪ:Bሎ:B9:BIL_STUB(@p:B:BPx:B":B:B:B:B:B:B:B:B:B:B:B:B:B@Q:B0Q:B Q:B`Ǫ:Bሎ:B9:B(@p:B:B`x:B#:B:B:B:B:B:B:B:B:B:B:B:B:B`Q:BPQ:BQ:BhȪ:Bሎ:B9:B@-, :B:Bpx:B$:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B :B:B:B:B:B0:B8:B@:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:BXhʪ:Ba:Bi:Bq:B:Bو:Bɇ:BI:Ba:Bሎ:B@:B:Bx:B%:B:B:B:B:B@ P̪:B:Bx:B8&:B:B:B:B:BR:B`R:BR:BPR:Bp\:B(R:BpR:B R:B SetFocusEnableWindow@ @:B:Bx:B&:B:B:B:B:BR:BhS:BS:BPp:BXS:B(S:BR:BS:B8P P̪:B:Bx:B':B:B:B:B:BR:BS:BS:BS:B{:B(S:BS:BS:B@8XUP̪:B:Bx:B0(:Bͪ:B:B:B:B:BR:BT:BHT:B(T:BМ:B(S:BR:BS:BT:BPT:B T:BpT:B؅Ϊ:BH:BhP@H@0  ;;ڪ:B:Bx:B(:B:B :B(:B:B0:B:B:B:BP:B:B:B:B:B:B:Bh :B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:Bp :B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B :B:B:B :B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :BP:BX:B :B :B :B :B :B :B :B:B :B :B :B :B :B :B0 :B8 :B@ :BH :BP :BX :B` :Bh :B :B :B :B :B :B :B :B :B :B`:B :B :B :B :B :B :BU:BT:BU:BHV:B(W:BXV:BV:BT:BU:BW:BW:BW:BX:B٪:BA:BI:BQ:BY:B:Ba:B:B:BGetSystemMetricsx1xP@ H@0 ?;д:B:Bx:B):B0ڪ:B:B :B(:B:B0:B:B:B:BP:B:B:B:B:B:B:Bh :B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:Bp :B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B :B:B:B :B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :BP:BX:B :B :B :B :B :B :B :B:B :B :B :B :B :B :B0 :B8 :B@ :BH :BP :BX :B` :Bh :B :B :B :B :B :B :B :B :B :B`:B :B :B :B :B :B :BW:BW:BV:BHV:B(W:BXV:BV:BU:B`W:BW:BW:BW:BX:BHrXS`SPS:BA:BI:BQ:BY:B:Ba:B:B:B@:B:B y:B(*:B:B:B:B:B@`a:B:B0y:B*:B:B:B:B:B(Y:B):B-:BQP@H@0 `XWH:B:B@y:Bx+:B:B :B(:B:B0:B:B:B:BP:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B :B:B:B :B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B:B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :BX:Bp :Bx :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :Bhg0:BA:BI:BQ:BY:B:Ba:Bi:Bq:BpP@H@0 ;;ڪ:B:BPy:B ,:B:B :B(:B:B0:B:B:B:BP:B:B:B:B:B:B:Bh :B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:Bp :B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B :B:B:B :B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :BP:BX:B :B :B :B :B :B :B :B:B :B :B :B :B :B :B0 :B8 :B@ :BH :BP :BX :B` :Bh :B :B :B :B :B :B :B :B :B :B`:B :B :B :B :B :B :BY:BY:BY:BHV:B(W:BXV:BV:BY:BY:BW:BW:BW:BX:Bh:BA:BI:BQ:BY:B:Ba:B:B:B `a:B:B`y:B,:B:B:B:B:BZ:BF:B:B(@:B:Bpy:Bp-:B:B:B:B:BGetDoubleClickTimeP@H@0 x;;ڪ:B:By:B.:B:B :B(:B:B0:B:B:B:BP:B:B:B:B:B:B:Bh :B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:Bp :B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B :B:B:B :B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :BP:BX:B :B :B :B :B :B :B :B:B :B :B :B :B :B :B0 :B8 :B@ :BH :BP :BX :B` :Bh :B :B :B :B :B :B :B :B :B :B`:B :B :B :B :B :B :BZ:BxZ:B[:BHV:B(W:B[:BpZ:BZ:BZ:BZ:BW:BW:BX:B :BA:BI:BQ:BY:B:Ba:B:B:B`a:B:By:B.:B:B:B:B:B[:B:B:BpxPX@pXHX@X0hX <::B:By:Bh/:B:B :B(:B:B0:B:B:B0\:BP:B:B:B:B:B:B:B0:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:Bp :B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:B8:Bp:B@:B:BH:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:BP:B:B:B:B:B:BX:B:B:B :B:B:B :B:B:B:B:B:B:B`:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:B\:BX:B`:Bh:Bp:Bx:Bh:B:B:B:B:B:Bp:B:B:B:B:B:Bx:B:B:B:B :B :B:B :B:B( :B:B8 :B:BH :B:BX :B:Bh :B:Bx :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B \:B :B :B :B :B:B:B :B :B :B :B :B :B :B[:B :B :B :B :B:B :B0 :B8 :B@ :BH :BP :BX :B` :Bh :B:B :B :B :B :B :B :B:B :B:B :B :B:B :B :B[:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:B@FF:BA:BI:BQ:BY:B:Ba:Bi:B:BhxX``@xhPHP@P0`P 64:B:By:B0:B:B :B(:B:B0:B:B:B\:BP:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:Bp :B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B :B:B:B :B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :B :B :B:B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :BP:BX:B:B:B:B:B :B :B :B:B :B :B :B :B :B :B0 :B8 :B@ :BH :BP :BX :B` :Bh :B:B:B :B :B :B :B :B :B :B:B :B :B:B:B:B :B(:B:B:B:B0:B8:Bh:B:B:B:B:B:B:B:B:B:B:B:B:BXa:BHa:B8a:BU:Bሎ:B9:BP@H@0 p0.д:B:B({:B ?:B:B :B(:B:B0:B:B:B:BP:B:B:B:B:B:B:Bh :B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:Bp :B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B :B:B:B :B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :BP:BX:B :B :B :B :B :B :B :Ba:B :B :B :B :B :B :B0 :B8 :B@ :BH :BP :BX :B` :Bh :B :B :B :B :B :B :B :B :B :B`:B :B :B :B :B :B :B_:BA:BI:BQ:BY:B:Ba:BX@:B:B8{:B?:B:B:B:B:B(@p:B:BH{:Bp@:B:B:B:B:B:B:B:B:B:B:B:B:BXb:BHb:Bhb:B@a:Bሎ:B9:B@:B:BX{:BhA:B:B:B:B:Bxb:B:B:B(@p:B:Bh{:BB:B:B:B:B:B:B:B:B:B:B:B:B:Bb:Bb:Bb:Bb:Bሎ:B9:B(@p:B:Bx{:BC:B:B:B:B:B:B:B:B:B:B:B:B:Bc:Bb:Bb:Bc:Bሎ:B9:B(@p:B:B{:BD:B:B:B:B:B:B:B:B:B:B:B:B:Bc:B(c:B8c:Bd:Bሎ:B9:B(@p:B:B{:BD:B:B:B:B:B:B:B:B:B:B:B:B:Bc:Bc:Bxc:Be:Bሎ:B9:B@:B:B{:BE:B:B:B:B:B(@p:B:B{:BF:B:B:B:B:B:B:B:B:B:B:B:B:Bc:Bc:Bc:BXg:Bሎ:B9:B(@p:B:B{:BG:B:B:B:B:B:B:B:B:B:B:B:B:B(d:Bd:Bd:B`h:Bሎ:B9:BW @:B:B{:BH:BHi:B:B:B:B:B@d:B`d:BPd:Bpd:B8d:BHd:BP8i:B:B@ h:B:B{:B0I:B:B:B:B:B@d:B`d:Bd:Bd:Bd:Bd:Bj:B:B h:B:B{:BI:B:B:B:B:B@d:B`d:BPd:Bpd:Bd:Bd:B(j:B:B h:B:B|:BJ:B:B:B:B:B@d:B`d:Be:B e:Bd:Be:Bk:B:B h:B:B|:B(K:B:B:B:B:B@d:B`d:BPd:Bpd:B8e:BHd:B`l:B:B h:B:B(|:BK:B:B:B:B:B@d:B`d:BPe:B`e:BHe:BHd:B@(m:B:B h:B:B8|:BxL:B:B:B:B:B@d:B`d:Bxe:Be:Bpe:BHd:Bm:B:B@@:B:BH|:B M:B:B:B:B:B @:B:BX|:BM:B:B:B:B:B((@:B:Bh|:BpN:B:B:B:B:BH@:B:Bx|:BO:B9:B9:BX:BPH`Ȼ:B:B|:BO:Bq:B:B:B:B:B:B:B:B:B:B:B:B`:B:Bh:B:B:Bp:Bx:B:B:B:B:B:B:Be:Be:Be:Be:Be:BXq:Bሎ:B!:Ba:B):B:BXnPXл:B:B|:BhP:B:B:B:B:B:B:B:B:B:B:B:B`:B:Bh:B:B:Bp:Bx:B:B:B:B:B:B:B(s:Bሎ:B!:Ba:B):B8pػ:B:B|:BQ:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:Bxt:Bሎ:B!:Ba:B):B0W@:B:B|:BQ:Bhu:B:B:B:B:Bf:B`f:Bf:Bpf:BXu:B:Bp#08p໎:B:B|:B`R:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:Bv:Bሎ:B!:Ba:B):B軎:B:B|:BS:B:B:B:B:B:B:B:B:B:B:B:Bf:B:B:B:B:B:B:B:Bf:Bf:Bf:Bx:Bሎ:B!:Ba:B):BH`x:B:B|:BS:B:B:B:B:B:B:B:B:B:B:B:B:B:Bh:B:B:Bp:Bx:B:B:B:B:B:B:By:Bሎ:B!:Ba:B):B @:B:B|:BXT:B:B:B:B:Bp@:B:B}:BU:BP9:B`9:Bp9:B9:B`:B@:B:B}:BU:B:B:B:B:B(0@`:B:B(}:BPV:BX|:B:B :B(:B:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B`g:Bg:BxH|:Ba:B 8`:B:B8}:BV:B:B :B(:B:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B0x:B:BH}:BW:B:B :B(:B:B0:B8:B@:BH:BP:B:B:B:Bp:Bx:B:B:B:B:B:B:B:B:B~:B:B):B@W@:B:BX}:BHX:B~:B:B:B:B:B8h:B0h:B8:B:BW@:B:Bh}:BX:B:B:B:B:B:BXh:BPh:B:B:B@W@:B:Bx}:BY:Bp:B:B:B:B:Bxh:Bph:B0`:B:B@ W@:B:B}:B@Z:Bx:B:B:B:B:Bh:Bh:Bh:B :B:B :B:B}:BZ:B:B:B:B:Bh:Bh:Bh:BЁ:B:B :B:B}:B[:B:B:B:B:Bh:Bh:Bh:Bx:B:B@W@:B:B}:B8\:B:B:B:B:B:Bh:Bi:B0:B:B@W@:B:B}:B\:B@:B:B:B:B:B0i:B(i:Bȃ:B:B@:B:B}:B]:B:B:B:B:BW@:B:B}:B0^:BȄ:B:B:B:B:Bj:Bi:B`:B:B@@W@:B:B}:B^:BЄ:B:B:B:B:B j:Bj:BX:B:B@W@:B:B~:B_:Bh:B:B:B:B:B@j:B8j:Bh:B:B@W@:B:B~:B(`:B:B:B:B:B:B`j:BXj:B:B:B@W@:B:B(~:B`:B:B:B:B:B:Bj:Bxj:Bx :B):B@W@:B:B8~:Bxa:B0:B:B:B:B:Bj:Bj:B:B):BW@:B:BH~:B b:BX:B:B:B:B:Bj:Bj:BH:B:B@@W@:B:BX~:Bb:B`:B:B:B:B:Bj:Bj:B舫:B):B@W@:B:Bh~:Bpc:B:B:B:B:B:Bk:Bj:B:B:B :B:Bx~:Bd:B:B:B:B:Bk:Bh:Bh:B0:B:BW@:B:B~:Bd:BЊ:B:B:B:B:B8k:B0k:B:B:B@@W@:B:B~:Bhe:B؊:B:B:B:B:BXk:BPk:B`:B:B@W@:B:B~:Bf:Bp:B:B:B:B:Bxk:Bpk:B:B:B@W@:B:B~:Bf:B:B:B:B:B:Bk:Bk:B0:B:B@W@:B:B~:B`g:B:B:B:B:B:Bk:Bk:B(:B:BW@:B:B~:Bh:Bȍ:B:B:B:B:Bk:Bk:BH:B:B@@:B:B~:Bh:B:B:B:B:Bp0:B:B~:BXi:B:B :B(:B:B0:B8:B@:BH:BP:B:B:B:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B):B@W@:B:B:Bj:B:B:B:B:B:B8l:B(l:B@:B:Bx0:B:B:Bj:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:BXl:BPl:B0:B:Bሎ:B!:Ba:B):B@W@:B:B(:BPk:Bȑ:B:B:B:B:Bxl:Bpl:B@P:B:B@W@:B:B8:Bk:B`:B:B:B:B:Bl:Bl:B蒫:B:B@W@:B:BH:Bl:B:B:B:B:B:Bl:Bl:BP:B:B@W@:B:BX:BHm:B:B:B:B:B:Bl:Bl:B:B:BW@:B:Bh:Bm:B:B:B:B:B:Bl:Bl:Bh:B:B@W@:B:Bx:Bn:BP:B:B:B:B:Bm:B(m:B@:B:B@0x:B:B:B@o:B:B :B(:B:B0:B8:B@:BH:BP:B:B:B:Bp:Bx:B:B:BPm:B:B:B:B:B:B:B:B):BW@:B:B:Bo:B@:B:B:B:B:Bpm:Bhm:BX0:B:B@@W@:B:B:Bp:BH:B:B:B:B:Bm:Bm:BЗ:B:B@W@:B:B:B8q:B:B:B:B:B:Bm:Bm:B`h:B:B@W@:B:B:Bq:Bx:B:B:B:B:Bm:Bm:B:B:B@W@:B:B:Br:B:B:B:B:B:Bm:Bn:Bh:B:B@W@:B:B:B0s:B:B:B:B:B:B n:Bn:BH:B:B0@`:B:B:Bs:B:B:B :B(:B:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:BPn:B`n:Bx:B:B @W@:B:B:Bt:B:B:B:B:B:Bn:Bn:B:B:B@W@:B:B:B(u:B(:B:B:B:B:Bn:Bn:B :B:B 0@`:B:B(:Bu:B:B:B :B(:B:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:Bn:Bo:B@H蝫:Ba:B:B:B8:Bxv:B:B:B:B:B:B:B:B:B:B:B:B8:B:B:B:B:B:B:B:B@:Bሎ:B!:Ba:B):B@:B:BH:B w:B9:B9:B9:B9:Bp:Bx!PP@H@0 ZY H:B:BX:Bw:B:B:B :B(:B:B0:B:B:B:BP:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B :B:B:B :B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B:B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :BX:Bp :Bx :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :Bxo:Bo:Bx:BA:BI:BQ:BY:B:Ba:Bi:Bq:B:B@H@0X0.д:B:Bh:Bpx:B:B :B(:B:B0:B:B:B:BP:B:B:B:B:B:B:Bh :B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:Bp :B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B :B:B:B :B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :BP:BX:B :B :B :B :B :B :B :B:B :B :B :B :B :B :B0 :B8 :B@ :BH :BP :BX :B` :Bh :B :B :B :B :B :B :B :B :B :B`:B :B :B :B :B :B :BxX:BA:BI:BQ:BY:B:Ba:B@:B:Bx:By:B:B:B:B:Bи0:B:B:By:B:B:B:B:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B 0:Ba:BP@H@0 h0.:B:B:Bhz:B:B :B(:B:B0:B:B:B:BP:B:B:B:B:B:B:Bh :B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B8p:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B :B:B:B :B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :BP:BX:B :B :B :B :B :B :B :B:B :B :B :B :B :B :B0 :B8 :B@ :BH :BP :BX :B` :Bh :B :B :B :B :B :B :B :B :B :B`:B :B :B :B :B :B :B«:BA:BI:BQ:BY:B:Ba:B@H@0X0.:B:B:B{:B:B :B(:B:B0:B:B:B:BP:B:B:B:B:B:B:Bh :B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:Bp :B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B :B:B:B :B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :BP:BX:B :B :B :B :B :B :B :B:B :B :B :B :B :B :B0 :B8 :B@ :BH :BP :BX :B` :Bh :B :B :B :B :B :B :B :B :B :B`:B :B :B :B :B :B :BPͫ:BA:BI:BQ:BY:B:Ba:BV:Bt:B8,+(:B:B:B{:Bͫ:B:B:B:B:B:B:B:B:B:B:B:B:B :B:B:B:B(:B0:B8:B@:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:BH:BP:BX:B`:Bh:Bp:Bx:B:B:Bϫ:B`H:Bϩ:Bh:B:Bو:Bɇ:BI:Ba:B0P`:B:BȀ:B`|:B:B :B(:B:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:BP@:B:B؀:B}:B:B:B:B:B@@:B:B耎:B}:B:B:B:B:B:B:B:BX~:B:B:B:B:BP¨:B:Bq:Bq:B:B:B:B:B:B:B:B :B @:B:B:B:B:B:B:B:B@H@0X0.:B:B:B:B:B :B(:B:B0:B:B:B:BP:B:B:B:B:B:B:Bh :B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:Bp :B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B :B:B:B :B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B(:B0:B8:B@:BH:BP:BX:B`:Bh:Bp:Bx:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B:B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B :B( :B0 :B8 :B@ :BH :BP :BX :B` :Bh :Bp :Bx :B :B :B :B :B :B :BP:BX:B :B :B :B :B :B :B :B:B :B :B :B :B :B :B0 :B8 :B@ :BH :BP :BX :B` :Bh :B :B :B :B :B :B :B :B :B :B`:B :B :B :B :B :B :BД ݫ:BA:BI:BQ:BY:B:Ba:BX:B:B(:B:B@:BH:BP:B:B X:B:B8:B:B@:BH:BP:B:B(@p:B:BH:B:B:B:B:B:B:B:B:B:B:B:B:B:Br:Br:Br:B߫:Bሎ:B9:B(@p:B:BX:B:B:B:B:B:B:B:B:B:B:B:B:B:Br:Br:Bs:B:Bሎ:B9:B (:B:Bh:B:B:B:B:B:BPs:B@s:B0s:B8s:BHs:B (X:B:Bx:B0:B:Bxs:Bps:Bs:B:B8pБ :B:B:B:B X (U X:B:B:B:B:B:B@:BH:BP:B:Bs:Bs:Bs:Bs:Bs:Bx0H:B:B):Bш:BH:Ba:BX:B:B:B:B@:B@:BH:BP:B:B0 (X:B:B:Bp:BP:B@:BH:BP:B:BЏȏX:B:BX:B:B:B0:B:B@:BH:BP:B:B`PX:B:B X:B:Bȁ:B:Bp:B@:BH:BP:B:Bx:B቎:B:B:B7!A  f n`fp38M @(GM@:B:B؁:B:B:B:B:B:B:B:Bߨ:B:B:B`:B@:B:B:B ݨ:B ި:Bu:Bt:Bu:B:B:Bpu:B:B:Bt:Bt:BP:Bt:Bt:Bt:B(u:B8u:B:B@XXHH``Ѝ`RH P PȍPh   (X(H(`:B;:B:BḎ:B:B :B:Bو:Bɇ:B:B:B M pr bnbpqË@ W% @:B:B:BX:B:B:B:B:B:B:Bu:Bu:Bu:Bu:Bu:B:Bu:B:B0:B:B:B@:B:Bu:BP:Bu:Bu:B:B:Bu:B:B:Bp:Bu:Bu:B:B:B`:B0hP:B:BḎ:B:B :B:Bو:Bɇ:B:B0:B @ U@:B:B:B:B8:B@:B:B:B:B:B :Bx:Bi:BA(F FCX$HoUL.)9)Vj_`t _m_X`Zk ťo[%N"m%s/Ԛlpj/ p/6/PXb[0}u-5 _Ѷ|W-w<`a r?V6@ jH|\e0  "V)e-2YC@4H0vPhC"lu` lЂ)Aj* @ ZA@&uw}wYYYYYYYYߔVݱڍݸG"QXm3N+9՛X<,OT X(I|xDe *0r2к62:&ט\ȮZ\F]=guEߘ8F`T ܗaR%{L <.6ډn$2h/q1`P( Gl5@GLAI[Qa2*ervi!r/uB"PQ| #z8F=BU%jj \B-_gk\[91*& ngcS Ȧ~oȦ-tݪe/LJyLs۳0ĔnTbOL>^z6mb3wٳ:Nkdr3mG5oJk=,e`󏟓p0٣Cm7TXѼ3ygz j]u- u)_RU]un+>~Ϲ\n*p Y, N=Hh1vc sQ"\DoPG@0A#0 bYpҜ .CSsA˷,Q]?(unˌ\R6oZfm5ma@_ʌs{99(!3Z,"2l`cF8>#eU@b@`X+imgPA{9Nn{z%%%%E|?::iw/;qۙ??˅y9g$c?[-UO g[^Ӻoi/h.N]C7 Ѯo3ɧdȔbv7)%;m}9;e|9596aznuZ?9Of zPd^hzPd^@ ]"h!J FQ<ًϖ ޝh%[}Ү(oP yJQ;%eXPaلlBMY۱D lJͺ&HE`EBl4H^^kXt.UvF*ocã6DJ@3h`9"k̤@ zp`Yr &jcPYv-BLs$BN0԰z~sjs ! $V(.BL$BN0_9u ŚM)El$v&-BLs$BN0а_9u Śͽt?p !?((*BL $BN.w^?9N5(XTFHd vФ^ͪ{7pƑ/h" Rf@Je`wAv]KKKG^Wz*ɭOK^& zd^9L*gymbmmmS@'P9B 8>0 m"Y!rh׳FĊ/O^Q6Pxx(x@ jvNr0<@  !Vn_@ B@o䕛j @ā!@n ]@ h4i,乀 W:yZvnnCARp t#\(B1X8ԃA y"M**8 N$- ;E*P`0( `0d @'#ޤruBFG fkr=L+d>өz__,@l_:bt]+SKHHH@BBBfWB:nP kb _:^:E4G˸D*# #UK'U> !rɞ"@)UA/}岎5?`SoֻaP!ro^!K5?!Mi>lJװO݊\ rGh.~^t(+89V9łQq ]1F_j'ߨ#؁cn]Wz55^?eh(^?i?|uS=F1Ϸn?ϝZϪc[ȫH>=2A"ӗx^7&̨߲w\5nGe $5lw9 g9WJP?8?:7rկAgdIVIgX#?p%s/|OlcMiWT)Պ\^lû&?O^ŶdW?8>5U +p_v I*p?Fv  HWEEEEEEEEEE4@䑁2o(yu[&:(2h77a]HZd"AA0 ~+?]Ӯiiq8mv!r:9A vXq`E_UH(з,=w>óQjew2R 7?3 Uoh öaDU5,{{{{{{{{b[[ p5XVzռKh륭V\ w"RSJr)rJiRN):W/ :{> ߲{v=28CplCCh5d ~.T}^A#tnGѨ]0 ]ܢV; " a-*k%u*8~ f G4O`D #FBig)8 Ͷ ?1&RMgC ?~mAzԩQ*( @!D` @g#S2X@GDN15{EL<U/_\a0qyz嫚z bp Brieq4dBb`iv[\:ٯy2Gͩ@ "6*hr",MWG!)`( gPt( &Ä,"b @H+i(_Ŷ:(SjM;ħ :VFL id."dѫ:[czT;IaJnI[pX?"[^sCj0vǹѥ3r3M5:F`]c}w{|<D f \:3ŪlfRmל]vd{nA fn#"բ׶F9/RSxjsU$/V:sbtT: @B$zUuȨ\߻w8NFp]Yv@*łZvMVRg>;[\~,"@5&WIyLʗI+}>ͩR ]VūەSHo J<]GKqD$k%jM‷"^/=:d_xw ~o\$tN"L>Ѯ Fi zY"=;=]0,e2Zf]oc,6f=Ŧ9:F 6@;pQ#m;4PRcL=^bl* OqʳX_nӲ\Oc̻h5M nMnM|c-k!M>HF棑IՌj_𓾎KTk x(Fcn;/qpŨMTњ8 Bn@.~c N0Yw+%+%Bj@.\cڶa e (RjhdD8%@jਆN0!FlIhѥc ê/d1C̚=,R0$IB``:.cb`x@S\ 1b4b=51";b"8 ׹cGzCܞ}ۆY66ѩyGԠqYro6t`L Y"pG?."*bq]91!Gae)XY׻ ٬h`*9NxScITR<=# җ u_u:0 h<:OxZW~^zޯk\<8 'r\.rL'd:\/pp8 D: > I|Bx8%BW2Ljf6QyC mE;$';%JSjհ5.{ bcYϘ&5 q#]ٯ 8,1)knӞ(HcSZv-dM{[[&M4iҤIKK4ɗ|ɗ|ɗ|ɗ&Md@f0 C@*i!2;B]M2mYպ"!,pM (2|$lށM8PIZg& T-AF`1( `0HM9&*5 Clլ?P^ϏvjΩwl^uhqqqqqqqqqqqq_լ$}T(`b%;vU:Fj>^ѻR ?:63 22V}9uhw;w;3_ lVTV+K )tiuqQ(??ruV;&ݼf1Gw/cvdݤeߦoE]"1w߻NiT?? eSjٴllllllllllll€I  BPp4d2 ,ߊbWeعK{UbX^EWիUzU^E ?W>®خאА4T@Em IMR<3@T`A 0 `0pCnmr#C bTQt ----_?_a!5Ӆ 05JLIfle&ٰ$ @IVBkԚ+~K|Ec˭1ŭVmlylm6,]b7V&v݄A&v|b7M&vǹSS63qzqfq8踕-?~dSJRRk))@JJ VۍEEE%.Q5BLn| j#P("lf 'Ɖ`@JЂ0( *!#@> !+++++++ '5f~Qثp8m87nR`aafaas"`/,`h%tz;4/ {%2ps,g+I5'*Ru+Q,JhFCctm˚TyM6FF6%~5NdR1i^n'(Lv*E522rj /;(L"hf`'"P0( A{P0:"sT|mEm----u\|7&^C8?J5}klfnZp?޳S.>'6YM2^'e3U~Kf[~>>J/MUJ״OG*Q =B+?'߻.ʕl~#~YunZVn{ {!>O>ݱäA0+*,gM5mtn.ճ ~YnI @+zc3 5@q[,nP](U"le` lEIQz,*PAaPx4!$cOVVVVVVV߿[}C(`onUUjQc`U3Q9TNRhk:[~}@`J'mS?.fJ"fo, ` F0ls& ɩm_n2Rs\⒒[6mMw˲h\6~?ɔb$SV;i;7蜢[;ݯq[-1ImLb$1Bf䧃Q9Ҏ ZA^UvjTV: Y ZSV`QY ˫6ז`tt$$B` Ʉ׶Sb+Ru=h"܄$P0(2(nگٕ5ZZZZvMNXͨWڕ"XG8`t*@tpmՕr_q,v{VebRT}kFس>eV۵BcX*42a.lT-qjU#I"?PEf8f4WOу ɨC&K>)L,dbYL5f}8.?߸n肀V"Hpbs"#Ae3 Ul~rlr= fx+>V"oz>)6П7:$Jx_lW FV,%ixݿFk0rtpHZE%ZakdF]P#3J۰6l܆E+hNi Go Z)椰~E6i--B2 ł7+?p@T_0mf &hE"\ehpNPtRFA`# eKتf%xU>J5X|Y1SIl;zMCS yDuk*VmE.E"u)\Kdkϖ0"s%$nwPBp "&=,@@E^KKm9qh}йvM:&{Q/S\ѫ=:<:^AWp)[g0t"` 2lP@?Bn;g_Ϭ7ϋEyx^*ljLPUY u0Iٖ e  t -\Ht=MPm۶)r@q 3$m0$ ("I:<`  `0 SGI QCI^1fﬠ^reKmq;!cd#s9XdF3gho7~=ٽpPQRs}!y%" ¼pâ7\Be ƿXs̡QˑsM]؄Rc_߸_ktkUٌ+~YϩB°D4fF- f`7L:;1114}s&)7Ȇ=wqOC?:Nm'\ߕGxt<:Gǣxt<:䳯ؖ=eUOs9͊OMhV5t% >z&ba{WHĦݸ)kG/o7l^b6E-^ =$Ųݽ '}؆e:ڼoiM”ڀȣ'6rzl^du]ؤvj.ZR hln>du]׭SVzv۲ήZX.s+|JݍvcVcMf&NV!mꙵYfYYw5]GnbZxn |]ml,1yKD[dґ0brRa?OC(zphyr 2hq|@@Al ~2đ"|XF/iږuZvɭ..A7\-yD_1Mk$ZNE`5.qUx-[[7ٯ}BL 2L  ~]n]FOs(2h$#2 4y@@pb,wD$Ue&xȊ$93 !ٰ\g/)"*|6,WE3J{CCϹ-z=k|mGh|=Ȉqw }v-8%E %=EBݳD#6s%fܮLpsح5xdnU*;?|Vx\``ϟO ?˯tT,*{ A\TcW8J>0{)J| ƿ sKφ FZW]u ~F?Ԁ}ߤ6%_DJ%?0\s#&siƄϩvfrfC*$"e/P PSvn;źm?1-.м/ze,n;=wZXdV&j @ + (-BLS$BN"4 ~t ǽ`s? ->)$@m_ևtŒB0xHk٠ο r9T *C0!c *Bl (DO" 0\@Ӕ_z~>5~Ъ}7/89j*[s (B̑8tXP: |%6CXUV#lx=io3` 'fx'2RH1@rȄI,YU@N@ ("lBREr `0 Ђ6R kg7kո0 ZpZ%tv]Bͫvc*۬YoPWz nwFٯI5qߢ?!8}%NoI6%&[ 0[vu_=H9nd:#MHg$*_8 PUQRB  ?@j0 "E;`E1A0Sf Vg>g{f}s\n=w^ϭOڥSi\RNp?ti^ee 042Y[h&$*@"daԚtZ3@"@QZj@  @ /]{etm YKz0!oKg5nuyVPB@"gp*A `A^Ӡ5 ܤ5=eiz9o@k?5Ku~H>{Q-h2z^{jO{[㒪9\Fћ~آz~IKʅ~ģnυVd=Yݒ7zCVѫRzPV j%mrM/)Ygw[sw]8ͺXGLBm*}@h @8PA2 5F/zhl:)B"l 8a lljq @ Z 0x6`|P%_ V"w)W+|qWV/+1.3I@/S?qj jX5 @5BkfQ EǢ X'iWX[)rcW?3lHk4Rbh qٺu_VU+.-[r/ۖ~rO^_R5E. mߍfF2h9D H 2u `0 :G>膢lY>ddj,n9s+z""$Z3lc5:~V.Sd,RZ_8^Htr( N Og_r \B.!K%Ҹ\B.!7ߘr~p\CSO'qw~}gv_vR|_~"WDB?BQ#7#mV6pw)*(KklSc[7J^[JѿaSTh+*0 M!KͶ [A;@@&$6Ǩ+!RȮlrMܴW4 ]ܶ ۲ yUly6I;r() s,Օ zPL>u >("K̞o7~ fKmVߴذhXk;ƪfSZJF%G%w BS7?0ii)`^\"l~`# lEIQz,*PAaP4((4zoovu_\S7M+ HwL]i0ϰ4ˮ?QjTI_J:%*/y<kyrZMZZZZZZZZY (Q"XH{`:`@*Nb7+l"#?sr+sZʜeN2'#W&^ޛN6qy9ox&Uz ~_ekEFD` |}A7{u$~h}Q,&&/vgqмJ5*Z:^BR<bj[}"'`Ad*F"^f s~yw,6MJdI٤~}v߯m ׮HxoZ*򯸴U(e߲oٷ[-;N%wG_ ?j:/[_SkJ\J_OZpY. DmZǩȠ 1ZN..FMvSD0 jbĮ0>h"pX 0 FHR*c\Q+V*mÿ1)gIvf3?KdV/RRY<ߴ<6^x{[z5-*y5zfּ7t68Ŧci!yrnZ:y߶>IUwS+bbZ1>`gY<>;VLZL@Wn@^2Xƈ`0 `#rt,Q+~u ݹgWHDs࿄Js[p("LkfQ9υz¶*۹Y}ї"zM͢״ w/UmS˦o-t%s9\|_|2[OM-C-};yeMT 3v RzxHHHL{2h-`Sn8Rb @A`P d0psl x Ղ[b"EF=n55E45p?v[DžnI8̩'dN2'7I qK%s>[VVӓ=DZ5hvhv` Y2neke!?Ƥ ҺnoWZ@1U*FfŨbT1IG.g,r=g^_ ˪B_E#ֈL.db2LL&&s;㕜P4͗aJ'ctH[q-D.Uj]ftnշ/}ˌ_~Ĥ&π `_7?؜bmx/Q9UսƺPX\,lllll`[.@Q"F$Oy/f90}}(€ Ј. `0 @( @Tr*5=!Đ9?Diٴiwo|O!Ip9)N ">?;QёkjwQ}OSS}8$*A|4P ߵ54zzO /2 p23s;2ˎM/,YE*6JpGK7QWh}5@y5צ mʚ܁';D>t]DZ~/""NPM- Zfs/17a2ҊZװ+8}rBu"ɘ@0DFbQGNp#uTw;;E:gggg8Hk\{Yoi- "K r[~\Z-2t]ZZZZڑ;BZUQ"IdV9*'Y$2!N~խE7Zhmyv^;ok&ѰQ T;Nf57zFu=wϻtffzღ*YiǩId6)muJ-xt HHL N.U mUOm &xfmWQ-(#Գ>x׭DsGX"@ /vN"KjMj"v` iiIʲ(h"Ƌb/Ƌb 0 AdKؕatҭ6+Wc|>lq+sS?w/ѫ*lӶi۴mn`LU52W8U;Nzǩq70X sw_:ײåy-{t^L5yvUW^woӚfZ3Lk5sXML&KDc1јx{Fo00Coy4++Ll&6ۋfz;֕Zo(\sUܶYu &bmۢcZt"Zswwr;-nR4)4&ͩIsjҜ4tܤ95iN\Ɵi^^m@evkTQ'UC"q_I~T}7XN S}˩r긜ZN-Ԏ߼6Ӭ=wNi֞;sY{NH}wB"ѼLl5+&b3mhϵ{۹N`}sXCCCk jJlMrNՔٚb|Oa%@qE9|*Ks5$&z! +td`]Cp*"U4$L @( >@ 4a&bPṲ !bH "*!@_0 9B(ZO A}#SZ ylΛ%89͚׸LYYa&N@yj|nB0p;"1ҁ`_W|vEv>XD,6gU唬z$Bg"@ᡇ.m(Ҵ1l `߾}(1Bl$XM3F@-?<3|V=pC kiTz"܀  l Iim 4> [6kҹ.ͻ?*D~ U {,X59S׿o/I*D P m.G ?~ȋlyM5/$7T+T-@]r;wH.Q9eGT*+r;Nn'ꌼrկ('"R'wt/iSs7@Ad~xB :y$\ '~,2)BK0M;k0`Xk5kzw@:AE1 #@?vyy*z=Þaj/蒜j\r\P.XWwJ+^7}wMǭ4qѴG$ $@b(_aFra?"%HP2W;]ߕn5%?Ab7Z"dG޻?T=ePW=e=ZhCQ!ܾ-B@ nw;Zfvvhs3xdJ2@` R R2* #. `-2N Yr~˪C䷬=rVfUC70c=wn%"wH_""uHgd0`,0xxx1u~}u"綶썼jNۦVs< xl4FQh1i͎r&M@ bxq @#ba-!jX訡 @(a\@vu-y\@9B@ nI~=[}lJZ0Z{ v@@ ۔A5"xA 8GsĮ/``0 `0:@fQE R-ZF옢bU%z~r8_F{{D@P뷌v=;=?wbjX?L?`iխ£V}li4s9rNi4/$z4yh;o[?@6=>翄ǖ/p~QkYv@<ŧ*O] ĢyX;uS7HV%.my/Vmٻm,}tn1lRCSF)Q(elRL\R]:ݽI$`R0)L &I`R0ݯvuߺTUi~ tۄTlTBRI$ZR-TK%ՒjIZ_?[YٱJK@\/tWMb;nfy:w$.U$Zrͫ& t[4j]9ao%tٴȺ.?Aϩ)@.soVN ʰY3f@_UutNSӮljuu21-Z# H@   (S"Xz`T0 F b $?+ߒS[HD,3[YUnL{~}d]Uصf?*ַ|﫜ZoeYUmS=U6TV<63Aާt뉔nET V뷓-1q}KavKJ>nM3JߤSjj сǔ.i4jf 观@g0t=GXi+ϠCWTܿ73d *lhiQ'U뗰cKF bdDdD@E.~0E@$uJ C{cPB4H1r,m @1xuɰ0|u]-וx<%+N_IǛ(-zGMSH4ݎ$q_ImR߻&DoLvrq[|dJc#@7(qRtmn0`Œ1@*Q5i==??zCOyS94>P' vYXYM>޶Hf$€I 0 Be040';?C]I*iЪmg/iMi@䡡6|U:z72FTWW5@?5E9e3;GO/(u9{\w7ܖ ߲'cWT۱i%x,1D20g۳VqoyZdv!:vb|psL i`ahXF1Zl7m[dvs__f<+vqѱ}KRuz{|plZ;it*jHB:6KZ8v C۷}7KzBsW@U FCi.cg1̞HǺͻ2j vvfvfgvfD:BAژ0%` .'҂ ("ŷ̀ #g=em& ]`"(((u8{JOYqwQ[\ @}zw^^\.*3>\۰UmWn-Dþ Fh/}9^2b@0l5@jjFjp|@8$, `'  Gh@Llز_j}Zĵ0U?NLh«_<{L,,;Zïp+5s%()?_+"STSLѣqxtZN6iikm*ѿxV~ϺUJh%lB+USX$ qV%?TnT){zRo_,(@7&]wѩmhQQX~Z/}=Wuj Ul*m绻]־;sIDeR2(] ŭJwO bK%Y2mM}ip*˯xnk>?msU~Bc&QԲ5qh䁞<6̎ZJf'@!` b0Ş`֐"\fD1%`\O:n*FMdsʉ}|aDBEKZv /csV^cXUgaq7(bܡQZYꪥUw(ᅰ_z!JR \Rt%U"_4{ BsٖvѮBi힕jsO"9݆y)6ts$ @2Y2܄jԢY0VT?SR'SÞa!ŏ l[(O"nqV 0L`}i*ʭ4۾6PMe]cl^eTpn[P8oZnmR˭&ڤ[r˫S߫u^#|"W6voO*6nkUSxoU;YmO܆UyYޗ};~ߘ5bޠ;2W䳺 &!7^ mL]Ƈ:_USr[T63}9S+ؔԂl~5p YKTR^Y **F&%U1eV NND'Ԫ}74ԇSK<2G}bvCvC^<ӺiMoYbRվyU_kw<:yitJOKV"3gEb߫l˶P+X\Vm|%RNM-rkZޒ%0H,9}NVCh`"؈pTP6PI"jFwO*xmR6)MJ&er};n[:6?_'_*p2ͮavm8 |}W$>կG]],-kcym[v˫5 (C"\8@@(¥%^zVU㴴 e[uY-׽wWK pѿ*ZV=rUU~NZylܦ{IO("x-|`ClȋLҒ,ޙ :ЂAaPĠ0  @@$ 8CYs(ARMnhn@K{?"H0ǧ_ZZZZZZZZ[˰i;w01M*nG}Um۷[0Oj[^5aچ?-a ˤ5ev6wZmsMc<Ø7᳃*>}߾JVm=}վ ɩԜ3ìey-W̖e~kⷬ 222 lj꺮\ vpݶ. SfTڛx61*6|eVaU=s_t^p鼂qn)8?f?vK>m- "Cf?gT5F]M+|&_3klm;oYݶvf qٸl\6. &2O=ͬj?sF/o@a#^VCB4tA"_Vy Lj .ٱNP۩j;j`Z{K oE6]vlrrp؜vB;yy8d_rQKo0J~׮KREF"p5lha G{( 7yQN7C|}r BNn]NZj^0̧7$2!T0| w98|$cԲA>MlܞzB[Pu{dJV`#SYAN@wv[f)X4+}U_#!PjTB?N2 0@!jx9:k0`N2mmhBy$>_r][4h"XE-Xs]h"X8hP2iO*Me$@ȌDQjhk='Zc0yy `.)»dL `WCQ SD\".o hHg"Tcyk^t4AtSpai뺮۲((`!(( 5bP¥@ BGc2YBe`PEGc2Y&zPHYZ{ "%_Hfx @л.{`mu+,=XZEVQl_hu 8zN~a=sn&][ JM7(q3dui0 h"Ǟ 3NPd]%ּRXW}-nm^¬gFs깴 pjJ5foq|t [PHH-0%%&B\i3K I n* @(ra:{} @BfVs\h:B(D`XEHw׹ F4Br(DYg ktL:m8nT0 @A+aIyXא0=k2lD HIM28h  `0 `08@ v)L0&l'R,VQ$s@P"Bbf?sj*Wh$'-m&m=mCD2-KED$Ӓi__~kLjiqQ)A#vfL+ve9` )n`)nyG&lY*Mfv_į*WUefU ,FgTPUq@-,ܼ֩u 2 u@ ( 835 tPtji fi/iC< ]PaQy6 `:U#t69`K\R?/pCG/{_k ӯXߛHH"/~^!әuv~~dv;n?T Ͱ&mg g$ӮLaٵpvz]7puiuq bZ"=*(i@[-ppԊxX‹84%PJ,l70 dH=m5p-8}^Z+UG P|;W_:W~W'_'> @lԇx` A0&F)l6;> UI2 NTG>oﯾ맟>#~#h_"eR1 6CƐ1d C81B(.)Ђ Aap $gȶxN RXyXH&鳎l/$1:oS }񻻊 `sT 6M߿~u{= s\(U\n-q0eRaqjf[U+Yn/55]  STzu|t|:>Oc-kϩw9!q|zn=ŷX׷ I0-Mؔ:5|?H\vϬN _?I;  |zv݄&%K~jM _()t{%&R(?+:?ͮ:.}4?K6!F1#8XԺ@j`` =b\^C "Ypg@0`K&vk.lŎX*-ͳ3fs]{qvǤ1/xs+]8Dͺ:v0(R"lr` RBh< @jЃ"0``xj͂cEd״s䊖U*`߲iooJ+Rlw [-p' ;xzzzzzzzzzRΞg`b h"h*2A% T5A F7OZZZZZZZZZ2~۫y((X*tIٳiծe5ؒgִy 70[L)9Bf@?VZmy_/l2+ @tآ/R6 s׺-*>ϫ_IfM{e]n᭶[Zcc5 ]b$sn+ &_ >lԫRZzvlHg&VW mZ}9ao9!uKI_FNG'e'JլK'-BP*ԖyEGT͎]#@ @n_$BN:`#." U;c74D/D1([˨2So*ޜ65$k!L  l0@bxb:a+@B]"Z~V.sT , DQ@ډ:2lMOArNB!5V]:%0LfB&O?w_?? ?@@*(;A rphP;U@+ @di^prMxMyj֥^bvc8=;B B4d1M-P׌jFz~Z#[K2%I)6XeߢRà!b"ls1Gr APȉИqGZ5>`T֔]`_]*6s<i_k(7?r&'&1Lb&1(?׳\B"S./U9q,;a|+TNMf:zdh2ԗ rCPnȟg>ݱGF"%>ͱW?Xw7s[0= v*OE[&} e^7Pp(8 yct,BǫK]u %"4%)xKk"4 FB#~?zN][0˥R3Y6-%}95Z}tl02}dXVa1o~ BSl zO![ ,2$ g@ B$wdF77bt~2\ŚpnP6 AWڔ&EFԳ1YU7΋pU*nmV1zA2ohemJsxǧ |J۰gU]jG /EE.˨Hn9WeQq7 [@b; FRv^Gp7:BiJ@i%r`PªKap#:BB4dбL.P׌jF̣R{fM%u+PH,ǧ΋upa@ B$w("fk`t.A@<KY0q9w ڔTJfM oȦ5jV5ЫX4BW=UyyyJv kȇK[ڠW-sGWJ4Rm#ZDg4{;Bl 2ԠHF9ǗVݱij:{ %wjZ2.".-l,(t(>(Bz@?u=%^y3P ;s*BF@Y/ބY]r*򃡓AབྷyCvq21D$hF"ߺMWB[qeq( 0erAas, {^I=wTm{6}G8w `@g*K~OguiwDGQvl:v4wcZ6ڣjc"1F$D@DEFDTEtEtEWdDFtEW3PcD%)@ K"xP `i0%M" ^fh'«OYU~O_Vҭz5Tq{za oy!fыBM6 nRU!!Ɍ_5jM$rȐA @gTl83DO^ŗięGB)K..3Ͷ/> F$lFXCB(!B aB-!j 1BLJ@2ъK, [2h?Bl$4N04_5+%Ze9nN6[֠3ډ\F;W ,@'BwS/-ʻa+  "BxA0`r^݂ixg8H @ Y0@#b8@Pm R3(OpIz$5/?3dG&\IEmP !1Xkw;% #zAZ B?K|b~I"&Q@jvЯ0L5B F@-ބY_rJ(éE"IN86 B r`׶I}׼뤣 0 [M :njN"뜺g׳%±P6kD跇Jhg;r8dJ1;LJd ԁǗ=J"Nǚ=a+6Blc(F"`OF' .J=R㹮oﰸ8,~2`aB g@?Ԙ~vr{Ih>BL0J"`OFD~I'm-i؜fѮaci.4YDtN.OBaA?}eFͫ,C60.!n;.merCDd]'b9Ds  `{+P,HeyVuBϵվخCey9wTDzG)QW6,+{)r9iyNhDt!(h*"1fe>G\nzUe9WwQA}58_#s KdaE?4U9. UiI<{ŧha%4{z=BeԪ5.VTBhl~6b4;~Q'E("/@dA 0sǗVݱij:{ %wjZ2.".-lWuF P'xÎD }jhK1Jc͸;O?WQ&tNDe""fw bv"fwL|͈c]\ ˧F*.c3-5ir[4f2@c{0\&$U-&pD36KxDDDBf<ۜ /p(Z+L]!"fw@b~`8@ z 4ǽ/;ˎފ (2L 3NP@ @` ;)! _+ +6@>ǰlOYW0+=~?L>_7~wJ>~oNF2#Pu\x-2j~4qպenZ 7@$"c}/0XDf9Y+{^n YU +q)jG.ұ)R:ܱr){^z7xydd_߄R]56èG ﹭I;CƨvCW}tӨaJ+=m):4uS÷-;|~QWܛ~(Wޞ繣ܘQلX(:VU\\r?Kn:+ro0va2ZtX{!G0,DWM;E5hG7zsʨ7nyYFe<2tuY!CwsU };jg=Y_:Us a_n0HtZek[ə-%ZK @K@@EDrpdbE*8B@F@$?Ty-Պ_55?yT^:@ԊvCMa6ZI'Ȓ/R[;+0BiK7UZV܃ 1RB1ƘsN)! @v,] #(H=}dOeGyi' < wFHgyuߊ]0~q-ui}{ʯh~j?g9iTIӂUUHV 6H6[p\W)łպĊ*N(eWՊp]jI2 n\e3LTJ\ĭݳU6jߡ{z=mT6u-xX`&V Ÿ[kLSmlņg`Fmм5{kcר&c5ƥy].ǫX-(V;jMXMƟ[mb&mU6|%6+MUe6(5/t?q ׵zeROOJ~b b.j3D @DD@s0|D tB:.1j̹%b/b#n:F$PKsev[CAdYooD(rp ;- Bn`\݆Im8j~%0'bPJBc72L BT(_j˪i Y0@LD(F",S@ @ LLY9&jѾťsJv+qڼo0Y ดE6Ѯew|g`͏/xkj^]Ŝp9n-;;;; B xY 6z0|e @Bd@b]-BLs$BN"4f~9u Śͽt?`RX B+c3 1h*Blc (DO" 0`ٗbw Պvώ]`0)6R6zn` H1 O(AHVXRK)ͫ::|U̺ʉ%~K;jo0ɬiC!32L4׮WΣ=a Po=f+nj-?&+M4+E%Bsniv5F)]:V+Fjy׼T|nzaOjwIՎ2YF;9K^ޡJlNݴD$gSǼȈ^}V_f5]pfsb{[saG9`Z^Š$g(2؅KPl6QSqS5hF2%dPW23!wwC@TL!J~-[o dbFX-F0#r1k 15 F' ս=3r(rx჉AE25Ă FN+ ս=3r{nw@pM䳜v80,2R g Rh ?"\|" b+/Fm9@ 9LG'ьNCAm6 0]Pf@#K00z9;,eP Q@%;B@Ulsy.Ç<*ͩViN޸c#SFT : (]P@!$ 80NFs/gP QUd+z#mfNZgѐ ""j&"#""0CIgB \+An0Cd)Ag"/\$v.jqlAE`nݵ[_h"HH0@F>qmRZd|J_~|iڛC}"TSk>!I#h":H0@F>qmRZd|J;|cڝCx_wMy8\>6BLS 2 Lovex6lQ&ötF.# @:s(+-f4M I,<$Bzo^ZL[z՚aYRkbРPa:"/@ AaG`bS/w|gհgw?ZM)zS-_Gjv?zްn۶c @?Eda@a_°M4AB`pc3!QPm d[CħA6N ݚ7S` Q߶o.fm f[,)RE{7PV4 ~Ut}wߴ/(w rgRR)~Ok1''mxUB*%P'\p،m0##HQm҉-UUZ񆟇 ڶmjz0?0@"bpʊ9h"d?HheM`M7Ͽ_qa,fɲК7b[\(lhNjhs00RQ*jT>ܑ+ kM8CpPGa_UUUDn02܊*8-%: H#:)'N@`eϲo͚4t ~ዮ(S* ?uRݳY~b>zEs`{} (0yzzzbI`K0 5zq #f` U? jʚu&g0 BUu7;,j ˋ, @.^0"l#a4Hj5G`@( \T(of7ˍ5dXQGGj)M&հw7&XYݴIW,W\KVdUm%.o7o۸>oN'"w-}PGo{Fe,?wOS|~2o|rk$3JM>e7mRF)\ 7H `$56EjxNE/$@}T XM`%x饧B0\:OBgJ:55d]C&p˗?_|ɓgϞ{ɓgϞ{˗/_|xh"h JgMCF>$%/RTEi|amNpF8kTweR5X 0)(n"B hЃ62A<`>I %.O:"FLQp\Nn\KKK˞|z߶o݇&ȗ4lSu3:Dv3Py-[*]1[%q?~Iw?_]mVmL3{dU:#tF:#}_ErѺb4-QVm!y-",?:V7Uf5DpPpoÔVF)<)MJ3ݣwM,=fǨH2hnA @)h014YW;[0 Z\\i&d /86%܎& ~dUb ϋ\gԜtF)1I&zuM2ѫ;8vCrИ:STcFN%qY-:-{0M MjbgCcCcscCccC@bPXH` ["hCR$%j@(xA_U510~s.çY!lxg1Wx܂yTslvǺڱY~۱ks[vϰa?Mh v j:Zp{ճ-ӹyn۞}7E$-:q]Ej{Q(fuGڕx=W *~xbߡuBq_-.Jfi˖Z?G@F @cPXH` {P  (1B b$4 J>^`2zu`ןjLu{vh-p0YJ MUhp2p| @'-u`Fɽ=Mbç>{~&9ݫxvB1q!y͂lY3[ fElɧ_r}\KL؀[#3\n=|z¨+ kS: :䚓_mfNB32c0f 'fHbG^֍3AHtۖ$ "9*Y+ 03[7-\6ݺdn ўv`2v @({Le2ރB ;99{PdBY "؃.@2z{3w9~4ډHz뵝ҮWugb]ݳL h(ClC $F,R8msz=N*'(nUɤsQZcCwdj#szh5(n5xlNxͳC8E+ZffEHiiq 66Z3lcI1JۜZu8*'-oB4&2r7lbXYjvpV tBL>dU|Ȭ@ Bo@RC#DJL%!Ϊ6%}`&R dvCMLfk!~BJL5ߎKo?MqH)1c as)")^!@-iّ s]U? B! bȔh?a.'z!zm+z "#/!3}yU\=Q2X P0@d!6qאe!v @; !;\M&AM:l8 pNߘ@(’,j ^Ø̦7{S EHRtHUu0y f=SV8ˍ.uw?b06a8F8*e2tsUOU,l{]񾷾~T@(!:s1Zk{{syc9s1w9Ɯs93Xc1 S2hmlsTfe b0( `py. `<I08]_CAl": x.K'3Ը7#`BCiD"J?tJTo)`XJ6yiƿ r/}G{w_A\Rݶ"ⶭXerLQ/v^$T"3EmC)݆bC[&_!?r^rTK]\|^R!2="ɭ3O H\W-R?.C/[[dUd*`s{Ҧ PiO$bX?ei Ӭz& b0z %1(C;PL@Xl0v|HH숑xdJʱ`ÌXظ0N| !MR)1aS9SA=TFN!TcVqEWw~q؉Y ڤڬۺ[i\uE^^Q6 x=A$D@ p8p8p80Á@  p8p8a0 @  A ƁI4wPZ6-Ô° z8!?.O(\IHi,qȮ]RmV;ڮ=4:x YFb(ЊƤ9ljLVt ix-I>=*}&\=Ĺi66Ć?T*gNt)iWCf09D8D$p@!bCrpZeX/Bb0kᵰXP@rPR#5h27iq5iq7iq5Й.ЂA0( `PH #< CcupV 7q#tTr[f^#LrqFJ;x5Z{E'Y_:У;=<@G /o, |4? #9Oel|4+1wcNxj{lN=}y86zGͲE jAoSs+ m^a 0K'zySlhi͒w^3n5Z  S]DKj\FY/YuZ.`"OM/nh̠ ?u`bccc1Ff 6k2P58,Yi5; WY~->k6su.q?z,gȎyϘ,ЬY͚UӼ]mM\h,i1LJ h,A {g5\ת͚wj)lN 4YjDW@5z*:ɮ}fOBu[߫n{m}U궾W5%]Gf +|4jjj9M|d w [ƽzq{{qqqqqqqqu4~~I /))#vmm,z)Ka4@1 + t +tXȔ^ƞsy)V{-0-I$I33L%OhA,ЈQh1fkqG & 6N< TC  #H A $hРG9r8$ @B]134%*@ 5bUVs Ф&7I @"S-@-j0 ck@Giii׶Ls qLjr@zɃ'zXpq{ # Bs5_"\Z@GT 6(pd^[hiiiߟuUg=kdV{*QmX6k/ wʦ4|Tlt~u'f 2z>xyh"d @ !#h=gLKKK=2#s~%-R~.)xHIIIEу]q+xlA} Ajffvf3sX1$@ >(Y"| fa4ԧ'zБsdPLވ%PqZ;l0`B@?@+ *cl0`浖SJ;Cl8>Odzݎ:<7F) h&B (6N` 0 ,2;f\YjO+j032@+ @DKqZٓƷm StvpB E* Ej!rJ+6s/O1ԓSg\v+e.{P>}ӧO>}6j^3Ф&7I }=?>  @ e0@  @ zȰvǧ,Lq"؇pXMGӀQ۠gH qɫ[7vM.k̖:fӲ!ˬl0/w]]a*>O@n_)cx|}^]b7wkkFB#Ho~YGS0r i6䴆ٵ;0g*7Y᷽ޭL"9`A`d00?ťĨ÷p~v^-+\^_TMkeK{]kxq8hh"=`*A Pg}RRoԊO6m>ӯʧt;m4xn;/J?(eQY~ͫT@)z9ak  X0bP|`a&jЀZkPq4`7  jn0H'aʪ#d0?@hN"X)zP@d{J'g}0fgݸO>'Uxs#P+Yׅ:k:ԺR{)5 ٚ~n#+aE䠑)Ŗ'V:|~~U("=hd2tt]r.XFuR9=-@  .qz$#@ zhQBKmTDlҫ]Ǵ'cK@{Wf A "*"#b'b'b!r8Ac0n"&MpĨ@1Fn|"?mݪ+!?YaњBuCgPkXkվ>|C`U*[EV2),&xd"@Jeg9g!nj*̱|sN>71)A PJ)%r)!RBa_) B!21rxX0;>B$gD$ +i dG븸W_.twI,.b3: c:;My4\:%9 g!)1Ʃu;lxk\:Ԭz6Fm:3~kޗ&դKc<%&c`r: s&m~CnkנtK .\o̠;D"Z,Zr`kz-@ r8Ac0njzu0 .hzbk $.Pcad2=h"d@R@ N1p" ŀ!cȮ7P@ @ЅB4(G;*h 0D b ,x}p|j>Pncgg%;J+ `d{B:u?Fj ~uY Ђ??M.x0iqy ww 5!(?FkjMxlZUqc ~yNe !`z5l @@4<`LpO,bk#_aMDzPcE.epᨥ*.Bs RR p :)eч"ꭿ pBkT>'U_DžW`g%]vpp B֫~Z^ .s|2@3   &5BB0D s564ݱjڝ͍x^6-1"CDe08?@*rB[ j(u0 $'[0 'zYCa[ h#BLR L Tq$M h6BL$TN a{wvydNӏ"Z@ ^ t@jrAp j_jؔ`?.  ; /b*: /`' s!b|nBa;(s"FpcFZЬ ]l%iRkު[5Qf԰՝)hX ?*ţr節G.ɧNZ1KӊilN1mwAH'ݴ OQqٷP,*y2 ]|x\^iu\wۓaճ?4SaTrI|R*/?U;gj~a~-M([7dYz鷼ݒ,W WE?ovN;i4&U-,Ќ4{`@A)q"<!I,"E"l``Fk 5hw,mD|iϯX7+MJEӯkߨK5vͪTMjجo {nzo!?SujmIKnU3a̚P{]jy!;p2Eŧ b|`.TE]߆u!(gv&{֯[b5It^de|ږ{<<2򚖮D #J/BK]P @)BLb ,L\ ;:sp@:(kTE^b@5(!C%^b:(YҺ[D5^"b,u:" vLL?du@(j0I DXaT)p4(e2%Y<@E*D#,agF^}ii'*5!Aò$7t)p)Xi޿޲{ ~aW4Yͣ(FQSSc (U2HL@E*C#>qhspMaN mJKK`8N"ułۜl/z>ЃXx|TABdUP@e3my< wa ,iLf|}JtaxD&>Q Ya WbYƸ"S( 'ӟP'ߟ$&Y Kb(?  ( 3-=V"ܤ <T c]Ზ3_Q[brxRlY;bhdJ`8@@b(Xa%rI [TAtaƑ4eZeH z&((B̑ r 8yç\o("T{@O  Ć,vaBKDR|/d0s7;d5|¥ Ij K ^>A`- jఌW0K"$YH,G.N4XvNhw:}Skos 6{ccḩ92g rE".Q{=HĊѮ\TWBM@b|La %r@y"[ ("J@`$QL7}UWax4`P@%4d @X т@Voț?uI]@˶ -h"]HAA0x4☎F ]իd.Y[Q)y'SMkWutW߶[OhjUVsxXaq| q`qTЩyslشx\h!KE~a$jȰVp ~ jQ   @ @rxd/;8 @bx`PJnP :DcЩ' &2'뭽"l5T]@8eY H$ɺa@b|p`P$,;t\@KVhf A | &T1 r"5!W&;!ЇrԤ.IPzi\s]C@>Ae I$I0]%ɲ,˾/˲$I I$I$QD@:hazclAl `_2爩ȼAG@QT)2<&Hp_kke{uDk:v (mu_؄rհSvJJUC%rCȓo^77k;Ѱ$Whh\&W ChCrHN6-?1tLcR{[1;6Y9LN<sNKuڮm5*`kRvjjM&ijiߝng UFRqyT$n@.O=O٘{$s01A %jd|a`9T8΋-yETq7f@0Ʉ>A[s[  I!*~:uU|XuD^/tNʫX ǥ?Z^n]+2v Тb.@.fg[bVmU%um6900M4i@zf?U- S}T02Bb(6O LF/>yוb^OuXՒpaXݶzyCX<@T;`9ҦV(eШ 8qDi a@ atwȤN=j IB!to9'ٟxD`qF-d HҦS~(#Ba 0\ +830@   h'9xQj˻]n2`"@< !$K;JV@ Z a%N QD;IPBCVe1! lA'яt4ىQU5.xLd/6Džu_ 8LSr<@!R`m+_1[ZWu~l39avs\;斷q70@!)!R;R!RJyRJ)RJ)RJ)BJ)CH)w)\* # ' ,@ C,@ %-M^0@P(x@jPJ0  `  #a @ a0@j ߳0 a04ﰳ @j0 @U2rȘt\$18c0 B@oC$j) @3BR(j l0 V@8 ( 3&c`R#h"XfI`|U 0l"-D|oZ&&_`"#9I޲oI}O7Vw,պYC3O*9m kf˨Jܾͮmx]@ R zUr? B @<!n#5| @gy~{gEdb7T)s'zz3d00@@@@<%zY:{cA@FD@&c3 #P0sH @`B2ZWpoTJ<\H+v׺W˾{bxJa W @7QG <  %s_ph\:ƥy:^uv]+@,c@&k6,"FNEGdhU2Xnp `<4]XXO:r&4;g+խ-y^ᑚ3M!I>5"9|>ç$ .v+ /'c 9 ,Q|c@F@H2_$Ӛ۰Yoe}0@%rI3ta S0+M @F 1;;{#Yn }ry_,ٖP40 @  [0&b&1TA(+ '5CL ('3=Ų|Eo7i%%&.> J50d@ @  @1rxDd5 y"D-na@<5@!S=~f0030rx,@<@<C ^ʤĐ)]60RJ@HA"rZ 4M@*_2)@#k!@<@P@4c@^Fm]L2VRGIfSjx\L40 QQ  h_"HmDTàjcRw!7\5{q/j+;~]);""~":)T4#pԶ}XO(qxؔV5p|Jg5c& j(2amO@bPOa 0lf M2Vm:~'LShTjA@A)@ Q=yoء!@z (b( 6=y$GCR!@HARy 9YKYSyw20 AyYy: SyW b0 0_y& C `"yi9% 0B`"y<1`yk21 ypy`AKySySy>UyN 0 yN 0y;+ Ky/%y?P%@oy_S9yUyY%yY%y09K%y 10i `@y_y  yY& yYyYAyQ \0 +P1Py0*0yRLy0zVyYyVy`9y@!  ]"y)+<`!yp"y 9Ay_i 9PQy i``y;+m >0) A!y ]aP!RP,yc mdy;UyQeky Z,9%PLy yYAy~o9y_ ZL~ 0K\`QP yl&y >9%yc0,QKy   yY%ySJ JK yP Pydy }?oym 1y_Sy_ 19yUN !yZ"D J!9%@"J Jy"y 9!J)y- _y}}P>J `J. `o0> 9Ay~P"yiz  n9 !"yi  yi x`yi )`y4 9Y`y P %y hUy 9yi  yi 90O1yi 90_1y  P9y:;*`1K9Keyiyi 9yZ`y P`9y Pk`y99y {`y:y9yY|Xy29yiPyN y P& J y p`%9 y,ЖSC0yy/"yYy Py8?P`Qy~`% y8zPy89ey % 9Ayo "0 Ay*yYyYpyzPy9%yY~`1yYy*ܕYAy*Yy*y!]{{ ZSyiK 9_0 `#y)q:d 0yi, +Ay*hy* J0d@yY{/ QyYy*+zPY`Ay*py: 9y*+z )y ]P`9yP ey |)y* #P`y Vy:ɡ* RLLq<`AQy*w! ɠ\)y) ٲI{ 2Py;`y  $?0 QJyY%y P vy;Mr9PyHPy 9%y 9M|Py Py9y9KyYyp`yp`9y Uyp`y 9%y 9%jVyp`y  yt nPAy~`Py~`y9y~`y~`y|)y )y)y ٢k9yP ey)a  A{`9y ٥[)y9~H0 y  y "yI9QyUy ٧? )yy )n0y(`eBy 9 Dym P&yo yyXyJo)P"yY9yY9yN`9yYqyYqyܣ 9AJyFXP A8yPyYII˷yoR@yYI볤y@y' n0 qy8 y'Pj`y>yܣy 9Ayܓ(yAUy0 AJJJy y0 RyYyYy~0 `yYy9)y ! A)ykQ#9(:YP`!2XyI O:1yI/AK%# (`"!y\("yYy >y :yN˓ ٦ :yi C !yNˣlYy9 X9yI<ٗ  by$Qٗ(ǗO)0(`!yNZ P)0)`y]P JxJy; yXH9%yiiPyio 90Oi`#ySJy" yY%@yɐ= ^l< z`1y; 2P`9yB l`9yP( yP yɠ 0ymy j`PJyYy 92qyY%yey lk`A!Gy8y y8A!y9QyYy#mD Pxny Sy>Sy ,Y%yZy)y8yk 9AyYy) 9AjyܡNY!jyP yP yXy y<yxy NYjy'] Ay y 9y i  %ynuy8|Uy8 Uy u9y J }Py  n !y} Z&Py PV ``y&y.&y>P `y ~0XP2y K 0py>P `y} Z&P/yil˴ Hj9?cym#y^&y" %y UJyPPyPPy PI JJyϕjy.SySKyYyY`yyyϕzP P!yP P!y yϕ yiP 9EyS! y| {a9yk~ 9 y 9y Zk)`Pylo^9y]yY`yݖ~YPyYP!y\yϕ]&y?yݶk{@y?yݖ~Ayy 9y 9`ayP P!yiP!1)yly *UyN 9yy. 9%yi{P0yϕz| y P PyPEPyP Ey-) P!yϥXyP yϕ{&yP P!yyc<~0` y!-U P!K yY%9`y_r69I?yh  Z\[ P!y &@XKyil8  0&Py~Pt&y PPy P %yOP0 y P %y 9`")IKy}UyYI y 9`")y>P `yY&Py{ky_d&P`aPy̧o  %y 9`yJY9`yx y y0&yy.i03&yyI|&y&@yY` y  %20&@*yY`yY`y&y-0 `:yI|&yY0&Py ~ y 9PQy[ i``J Py^^ 9`a@yK&)iyy 9`Iy} 9P!y} 9P!y 9`y 9`&K`y 9`yzyyY`Iy \& y0+ 9`ayz F`&yJ &KyyJ&Pyh 9`J%&Pyh 9`ay0+&@yj&K`yHY`a@y nN& yy 9`ycy ާ< KJ< PV0y} 9%ymZ0P! @y/ ʣLP`yGm<0mPDIy| 9%yaZ0 & yj`&@$y r0^ VIylPIy Pyy 0~ VIy PPy X %y,|`Uy H Sy: ]0CPAy P %y yN  %yrP`%yP yP y  PyrPVy9 %yyy 9j`&@y rP`@$yIr9@$K&yrSIy{@< ]l00APDIy &yyY`y/y~0 PAqy_0< 69Pyil8  0a&Py~Pb&y /P;Py PPyOP y P %y~ 9%y~ 9%yiUy& @$y\l! ɔK&P`aPyL`&yy&y=P `yiߢI+&y9`K`ayP yY1x ZL&y9 %y}9 y*Y& yY&yY&yH 9&yJey= 8 &yZ L`yZcy9&y{H 9@yGyiʣ^ /S0>y[U0\JJ9K%yi͠i9[/ k9  `yk~0 `Nyk 9`yHyY`yY.  ] 0 P!:yY@yL 8`@y \HP@KpyI;h&y}\Y0*ky>h&yMeKyHcyYym 9y$~Dsy ;$ vA)y} 9y(pQyk\QyHQy&yQy&ym&y&y8&y]&yL ^ Z0 `aPy]&y8:8#P`"P&P`JyY 9yi 9Jyڕ# Ƣ qTP`2y:yYyZYyj^PyaK >r8 `!"y; XQ8y 8P$y(Zy YXy,y\Yy0jy>^h9y]YAy PyP y-yܒP Ay] 9ymyP y}9JyJcyJcyHJcJ yi `yHey9l I `"PJJy.ZFPym(jMPPym(jMPPy~Uy;+n0 Uj{0ey PyPy1jP %y 9iy LPIy]  P%yϕ[Y%yϕ[Y%y|Qy &yX"y$? ɡ) %y\&y\&yO&byHlj 0 !y+O ,0Y0Qzy$z<L:&0H#P` y_&zy79hy1 ɤO0j#P`"@yo~ 9yYN9yVyVyo  yo  y&y-&y-&y&y$:8:V#P`y=&y=&y&zJ\yey(ey8eyHe ****2*yX **yh * ***)yx*9**y *Y**yQ9*ym*:*:@J*:@Zjjjzj;jKj[jkj{j jj,j<Jl LRUUAUKUUUUUUUUUJUDUCwUCUC UCUDUD/USRnUuUkU_UD=UQUDKUUDiUDRmUDUEUEUEUEGUE}UEUFUGoUGUGUGUGaUF3UFOUF[UFUFUFUFUGUGCUUU%UmUIUB[UB?UB)UB UBUByUBUBUBUC/UCUUU+U7UKUUUeUsUUUUUUUU UU=UKUYUqUUUgUUUUCUUUU+UqUUUUUUGUGRRRRUSUSUSUTvUTUTUTUSUTUT&UT@UTZUTrUTUTUJUJGUJ7UJWUJUJ UUUOUqUU#UUUUUUUC[UUCiUUUWUUU@U@U#UeUUUBUUUUUVUUH!PUHUIUIUIaUIsUH;UHwUHUIUIUUUAiUA]U}UU%UUU)UCUUUmUUUU4UhUUU(UDUVUrU~UUUUUUU-UKUgUsUUUU U'UUU?UUU%U UUUKUU7UUUUUUUUUUUUPUQUOUOKUOUPaUPUPUPUPUP1UPMUPyUPUOUOUOU|UQUQUQ5UQSUQoURUQUQURUUU UULUxUUUUUDUbUUpUUU:URUnUUUUUU2URU^UxUUUtUU UU,UU&UtU:UbU~UUUUUUUUUUUCUUUUUFUdUUuU UUUUjUvUUU\U0UNU:UDUUUUUUVUvUUUNUNGUNUUUUU&U>UXUUUUXUjUJUUUUUUU2UVU|UUUTUUUUU?UIUUUURhUEU_U}UUU%U1U UUAUA U@UA!UA/UAUAUAUAUGUJUJUJUJUJUJUJUJUJUJUJUKUK UKUKUKUK%UK-UK?UXUXUX~UXUXUXUXUYUYUY8UYJUY\UYnUYUYUYUYUYUYUKgUKUKUKUKULULULIULULUMUMkUMUMUMUMUMUMUNUR5URaURURURURUS9UWUVUV"UV0UVFUVUVUVUVUW*UW6UWLUWZUWhUWpUWUWUWUWUWUXUX&UX>UXZUZR|RPRPP RRtRpRpRWRkRVPRRAR]R^RRRRRRRPpPYP`PPRPRRR(R R4DR4 R4RR"P,RLR]PRRPLRLsPRRRRD&PHRH6R\PPPTR^RTjRRTlR:R[RRLPRD%PLRD$PPRPXRPZR R(_PP$RRRfRHRRR8P4R4R8P,R, R$P(R(RR(]R(YRL|R(WRRPdRdP|R|R|R|PhRhPpRpRpRZP`R`R`R RPxRxRxRURWRQRSR#R%RR!R'R)R+PlRlRlPRIRxR?RARRR|RxR9PP\P(RLFR\PXPtR`R`PRR R!R RlPPPPP PPPPPPPRRPLRDjR@MRRPRR RRePR[RfRcRdRgR@>RSR&RZP|RP"R>RR1RPPxRRR'RLRR:PR!PDRDdR4RD\RD`RD^P@R`jPYPTPP@PPPRhP`PhT? T?P>PHTP>T? PPP,PP4PR`5RRPR`R`RP RiR`R`PPRJR J}RL\RQDRLZR`R4P,R`R`PR`P R`R`R`RoPR`PR5RR(R`RR`(PRRRp+RJRJRJRJRJR;RJRJRR4P@R@PR4P0R0A=R0AuRpCRpBRRRQBRQCRPtRLRtbR` R` PRPP`P|R|RFRF/PRRR NKPlRlKRlKRtyRt{Rt}RtPPLPRfRgPPPP0YPP$PP$PR,R@:PRWRWRRLdR<RU{RURXRXRhP`RXPtRXRhRpkRt~RhRh1Rh=PPRUzRURRPRBRDRt"Rt#RQRPdPLRRRRPRtxRRRtnRtBRR\R\PhRRt\Rt6PPPRpvPDRDNRDPRDTRDcRDZRDaRPRQPRRRdRhPRt`RtbRORRRt2RRLzP,R,nR,pRRcRRRRdRRdRdRRdRdPRRRRRRhRdRhRdRdRdRdPtRtRhRRtRRR(PdR0R1R(PLRR4PRRRRRRRRR R$#Rt&R R R P R($RtR LRR Rt(PPR!R3RR,R,R,R,mR,sPXRXRXRXRXP8YPHPDP@PPPTPRlRlPPP4PP0Pt PPPlPPPpP4PPPP$P(P P`P\PR$P\R`*R`R$P|RRR$R,~P(R,ReR$PRR$R$R@gR(&RRRRRRRR R@fRTPPR$R R RRPLR!PTR#P\R%PDRPpR+PlR)PxR-PR1PR/R`R`"P R`PHR$Rh}PdRh~R PR PR,P R,R/PR0R$R$RLPHRLPRRR`RRXR$RlRdRLRR@jR|bRRRR`R`R`R$RhRR R<P :BDocumentCreatedDocumentBecameCurrentDocumentActivatedDocumentToBeDestroyedDocumentDestroyedLayoutSwitchedIPEUpdateUICellSelectedSystemVariableChangedAcadApplicationIdle :B`@ :B :B :B :BUnlockedContentLockedFormatLockedContentAndFormatLockedB:B`@0!:B5!:B>!:BD!:BJ!:BS!:BAutoDistanceAngleColorLineTypeLineWeightf:B9f:B90茪:B茪:B茪:B茪:B茪:B 茪:B茪:B(茪:B@P:BpP:Bx :BTx :BU :BV :BW :BX :BY :BZ :B[ :B\ :B] :B^ :B_ :B`t@ :Ba :Bb :Bc :Bd :Be :Bf :Bg :Bh :Bi :Bj :Bk  :Bl@ :Bm :B:B:B:B:B :B(:B<:B=:B>(@:B?:B@:BA :BB:BC:BD:BE:B0:B:B+:B,:B-:B.:B04:B15:B2 :B3(:B46:B50@:B67:B*@:B/HX:B_:B}:B~:Bؘ:BPؘ:BQؘ:BOX:BX:BX:B`@:BF:Bz:B{H:By4@@:B!@:B"@:B#@@:B$@Ȝ:B(a8:B-xx:BIx:BJx:BKx:BLx:BM :B:B :B):B:B:B:B:B:B:B:B:B:B:B(:B`(:Ba((:Bb(:Bc(:Bd(:Be :BNH:BH:B:B%@:B&h:B'H:B:H:B;:B4:B5:B6 :B7(x:Bfp:Bwp:Bvp:Bx:Bj0`:Bk0h:Blp:Bg0`:Bh0h:BipŪ:BŪ:BŪ:BŪ:BXȪ:B7(@ʪ:B8Pʪ:B9Xx˪:B.x˪:B/x˪:BpP̪:B}@P̪:B~@P̪:B@,P̪:B@-P̪:B@P̪:B@P̪:B P̪:B(@ͪ:B.ͪ:B/ͪ:B8ͪ:B0ͪ:Bͪ:B.ͪ:B/ͪ:B0ͪ:B8ͪ:B@ͪ:B8xϪ:BxϪ:Bڪ:B`Hڪ:BPڪ:BXڪ:B@`ڪ:B@hڪ:B@D@ڪ:B@pڪ:Bxڪ:Bڪ:B@ڪ:Bڪ:B@ڪ:B@ڪ:B@Bڪ:B@Cڪ:Bڪ:Bڪ:Bڪ:Bڪ:Bڪ:Bڪ:Bڪ:B@ڪ:B@ڪ:Bڪ:Bڪ:Bڪ:Bڪ:B@ڪ:Bڪ:Bڪ:Bڪ:Bڪ:B0ڪ:B:B :B :B :B:B :B(:B 1H(:BHhH:B:B{:B|:B@:B:B:B@:B:B:B:BX@:B:B :B(:B0:B`:B8:B@:BH:B@P:B@\@:Bh :B :BNx :BQ :BR :BS :BTw :BU :BOap :BPax:Bp:Bl@:B:B@:Bh:Bh:Bx:B:B:Ba:Ba:Ba!:B8@!:B<@!:B0!:Ba!:Ba!:Ba!:Ba!:Ba!:Ba !:Ba(!:Ba0!:Ba8!:Ba@!:BaH!:BaP!:BaX!:Ba`#:B@#:B@#:B@`$:B`$:B$:B@$:B@x%:BHx%:B @`':By`':Bz':Bh8(:BK@(:BL(:BM ):B@ ):B@):B:*:B;*:B<*:B=7:B?@7:B@07:BA07:BB@7:BC07:BD7:B>a`E:BF(E:BEahG:BGU:B\HU:B]PU:B^XU:BVaU:BWaU:BXaU:BYaU:BZaU:B[a_:Bm_:Bn_:Bo_:Bp_:Bq _:Br(_:Bs0_:Bt8_:Bu@f:Bhh:Bn:Bn:Bn:B n:B!n:B"(@n:B#,n:B$ n:B(n:B)o:B*o:B+o:B,@ p:B.Hq:B/t:B0t:B1t:B2t:B3w:B8w:B9y:BGy:BHz:B|1`{:B(`{:B1|:Ba|:Ba:B:B:B荫:B:Bh0:B:B(:Ba :Ba(:B(:Ba0 :B :B`:B0H`:B0P`:B0X`:B0``:B0h`:BD:BA@:BaH:BaPH:Bظ:BHظ:BPظ:Baظ:Baظ:Baظ:Baظ:Baظ:Baظ:B1ظ:B1ë:Baë:BaPЫ:B(PЫ:B0PЫ:B$@PЫ:B8ѫ:B@ѫ:Bҫ:Bҫ:Bӫ:Baӫ:Baӫ:Baӫ:Baӫ:Baӫ:Baӫ:Baӫ:Baӫ:Baӫ:Ba ӫ:Ba(ݫ:B`@ݫ:B`@@ޫ:B`@@ޫ:B`@@ޫ:B`@@ޫ:B` @@:B @:B 0@:B. @:B/ @@:B0 @@:B1 P:B":B"`:B":B":B) :B* @:B+ @:B, :B- P:B6 P:B7 `:B0`:B1̈TSUWH0Hi Hl$ Hm HUrHM8H0_][SUWH0Hi Hl$ Hm H'rHMPֳH0_][0SUVWHHHi0Hl$0Hm0HM(HtHÑ9LHH_^][SUVWHHHi0Hl$0Hm0HHH_^][SUVWHHHi0Hl$0Hm0HU H IHEHtH]8HLHH_^][̔$SUVWH8Hi Hl$ Hm HMHtH[9LH8_^][SUVWH8Hi Hl$ Hm HMHtH+9LH8_^][,SUVWATAUHHHi0Hl$0Hm0H$HHA]A\_^][SUVWATAUHHHi0Hl$0Hm0HM`HtH9LHHA]A\_^][SUVWATAUHHHi0Hl$0Hm0HjpHM(HHA]A\_^][̐SUWH0Hi Hl$ Hm HUHM0'H0_][\DSUWH0Hi Hl$ Hm HUHM0H0_][(SUWH0Hi Hl$ Hm HUHM0H0_][SUWH0Hi Hl$ Hm HUHM0gH0_][TSUWH0Hi Hl$ Hm HUHM0'H0_][̌SUWH0Hi Hl$ Hm HUHM0H0_][XSUWH0Hi Hl$ Hm HUHM0H0_][$TSUWH0Hi Hl$ Hm HUHM0gH0_][SUWH0Hi Hl$ Hm HUHM0'H0_][̼SUWH0Hi Hl$ Hm HUHM0H0_][̈T}SUWH0Hi Hl$ Hm HUHM0H0_][TSUWH0Hi Hl$ Hm HUHM0gH0_][ SUWH0Hi Hl$ Hm HUHM0'H0_][TSUWH0Hi Hl$ Hm HUHM0H0_][̸SUWH0Hi Hl$ Hm HUHM0H0_][̄$SUVWATAUH8Hi Hl$ Hm HH8A]A\_^][P; SUVWATAUAVAWH8Hi Hl$ Hm HHtH9LH8A_A^A]A\_^][SUVWATAUAVAWH8Hi Hl$ Hm HHtH9LH8A_A^A]A\_^][SUVWATAUAVAWH8Hi Hl$ Hm HHtHJ9LH8A_A^A]A\_^][SUVWATAUAVAWH8Hi Hl$ Hm HjHMh説H8A_A^A]A\_^][SUVWATAUAVAWH8Hi Hl$ Hm HBHMPjH8A_A^A]A\_^][SUVWATAUAVAWH8Hi Hl$ Hm HHtHw9LH8A_A^A]A\_^][جmSUVWATAUAVAWHHHi0Hl$0Hm0HjHM ˫HHA_A^A]A\_^][SUVWATAUAVAWHHHi0Hl$0Hm0HU`H pAHE@HtH8HLHHA_A^A]A\_^][@T SUWH0Hi Hl$ Hm H !H0_][!SUVWH8Hi Hl$ Hm HMHtH{9LH8_^][ثd!LSUVWATAUAVH0Hi Hl$ Hm HUH @HEHtHM8HLH0A^A]A\_^][SUVWATAUAVH0Hi Hl$ Hm HMHtH9LH0A^A]A\_^][@#SUVWATAUAVAWH8Hi Hl$ Hm HU@H ?CHEHtH8HLH8A_A^A]A\_^][SUVWATAUAVAWH8Hi Hl$ Hm HU0H u?HEHtH8HLH8A_A^A]A\_^][SUVWATAUAVAWH8Hi Hl$ Hm HMHHtH9LH8A_A^A]A\_^][TT)<SUVWATAUAVH0Hi Hl$ Hm HM HtHM9LH0A^A]A\_^][SUVWATAUAVH0Hi Hl$ Hm HM(HtH9LH0A^A]A\_^][SUVWATAUAVH0Hi Hl$ Hm HM0HtH9LH0A^A]A\_^][̘,SUVWH8Hi Hl$ Hm HMHtH9LH8_^][T<SUWH0Hi Hl$ Hm HUHM0GH0_][ @7HIDp?HH ?HHH貯H"SUVWATAUAVAWH8Hi Hl$ Hm HUhH =HEHtHl8HLH8A_A^A]A\_^][̘TeSUVWATAUAVAWHHHi0Hl$0Hm0HHȦHHA_A^A]A\_^][SUVWATAUAVAWHHHi0Hl$0Hm0HHMh舦HHA_A^A]A\_^][SUVWATAUAVAWHHHi0Hl$0Hm0HaHMPHHHA_A^A]A\_^][4i7SUVWATAUAVAWHXHi@Hl$@Hm@HMHtH9LHXA_A^A]A\_^][̘j7SUVWATAUAVAWHXHi@Hl$@Hm@HMHtH[9LHXA_A^A]A\_^][DjFSUVWATAUAVAWHXHi@Hl$@Hm@HMXHtH;9LHXA_A^A]A\_^][SUVWATAUAVAWHXHi@Hl$@Hm@HM@HtH9LHXA_A^A]A\_^][SUVWATAUAVAWHXHi@Hl$@Hm@HdHM 胥HXA_A^A]A\_^][̈dmSUVWATH0Hi Hl$ Hm HdHM89H0A\_^][SUVWATH0Hi Hl$ Hm HVdHMP-H0A\_^][ nVSUVWATH0Hi Hl$ Hm HMHtH9LH0A\_^][SUVWATH0Hi Hl$ Hm HMHtHŅ9LH0A\_^][̨TpSUVWATH0Hi Hl$ Hm HMHHtH9LH0A\_^][SUVWATH0Hi Hl$ Hm H.HM H0A\_^][@tSUH8Hi Hl$ Hm HMHtH=9LH8][ xSUWH0Hi Hl$ Hm HH}7B8HEHH]3HBȅt*;HEHHHLP@;HHSHxH0_][̈SUVWATH0Hi Hl$ Hm HH0A\_^][TSUVWH8Hi Hl$ Hm HMHtH9LH8_^][ԅSUVWATAUH8Hi Hl$ Hm HUH T7HEHtHg8HLH8A]A\_^][SUVWATAUH8Hi Hl$ Hm HU H 7tHEHtH 8HLH8A]A\_^][hSUVWATAUH8Hi Hl$ Hm HMHtH9LH8A]A\_^][SUVWATAUH8Hi Hl$ Hm HH8A]A\_^][$SUVWATAUAVH0Hi Hl$ Hm HH0A^A]A\_^][̢tHSUVWATH0Hi Hl$ Hm HU(H 5IHEHtH!8HLH0A\_^][SUVWATH0Hi Hl$ Hm HMHtH9LH0A\_^][D4 SUVWATAUAVH0Hi Hl$ Hm HГH0A^A]A\_^][dSUVWATAUHHHi0Hl$0Hm0HbHHA]A\_^][SUVWATAUHHHi0Hl$0Hm0HHHA]A\_^][SUVWATAUHHHi0Hl$0Hm0H HEHE(HM HM(HE 3H;t HM_HHA]A\_^][TSUH8Hi Hl$ Hm HMH8][0TSUVWATAUAVAWHHHi0Hl$0Hm0HWHHA_A^A]A\_^][SUVWATAUAVAWHHHi0Hl$0Hm0HvHHA_A^A]A\_^][ȠSUWH0Hi Hl$ Hm HUHM0H0_][̔$~SUVWH8Hi Hl$ Hm HUHM@H8_^][`dUH0Hi Hl$ Hm AHXH0],TSUVWH8Hi Hl$ Hm HMHtHc9LH8_^][SUVWH8Hi Hl$ Hm HMHtHC9LH8_^][SUVWH8Hi Hl$ Hm HԯH8_^][SUVWH8Hi Hl$ Hm HM HtH9LH8_^][|$SUVWATH0Hi Hl$ Hm HMHtH9LH0A\_^][8$%SUVWATH0Hi Hl$ Hm HMHtH9LH0A\_^][SUVWATH0Hi Hl$ Hm HMHtHm9LH0A\_^][ķSUVWATAUH8Hi Hl$ Hm HMHtH79LH8A]A\_^][|SUVWATH0Hi Hl$ Hm HYHM@豚H0A\_^][SUVWATH0Hi Hl$ Hm HXHMX}H0A\_^][$vSUVWATAUAVAWHHHi0Hl$0Hm0HUHH 0胿HEHtH{~8HLHHA_A^A]A\_^][SUVWATAUAVAWHHHi0Hl$0Hm0HU0H /(HEHtH@~8HLHHA_A^A]A\_^][SUVWATAUAVAWHHHi0Hl$0Hm0HUPH Z/;HEHtH}8HLHHA_A^A]A\_^][LSUVWATAUAVH0Hi Hl$ Hm HMHtH}9LH0A^A]A\_^][ԜSUVWH8Hi Hl$ Hm HWHM8ØH8_^][SUVWH8Hi Hl$ Hm HVHMP蓘H8_^][|SUVWATH0Hi Hl$ Hm HMHtH }9LH0A\_^][8tlSUVWATH0Hi Hl$ Hm HUH -YHEHtH|8HLH0A\_^][SUVWATH0Hi Hl$ Hm HM HtH|9LH0A\_^][̰4~SUVWATAUH8Hi Hl$ Hm HU H D-跼HEHtHg|8HLH8A]A\_^][SUVWATAUH8Hi Hl$ Hm HM0HtH|9LH8A]A\_^][($,SUVWATH@Hi0Hl$0Hm0HU(H ,HEHtH{8HLH@A\_^][ԚcSUVWATAUHHHi0Hl$0Hm0HTHM(_HHA]A\_^][SUVWATAUHHHi0Hl$0Hm0HUhH ,HE@HtH_{8HLHHA]A\_^][LSUVWATAUAVAWHXHi@Hl$@Hm@HUH +HEH}tH {HE8HMLHXA_A^A]A\_^][SUVWATH0Hi Hl$ Hm HUH 6+詺HEHtHz8HLH0A\_^][̔SUWH0Hi Hl$ Hm HMHtHtz9LH0_][PtSUVWH8Hi Hl$ Hm HMHtHz9LH8_^][ SUVWH8Hi Hl$ Hm HMHtHz9LH8_^][ȘSUVWH8Hi Hl$ Hm HMHtHz9LH8_^][̄SUWH0Hi Hl$ Hm HMHtHTz9LH0_][@SUVWH8Hi Hl$ Hm HMHtH#z9LH8_^][SUVWATAUAVH0Hi Hl$ Hm HH0A^A]A\_^][SUVWATAUAVH0Hi Hl$ Hm HH0A^A]A\_^][äSUVWH8Hi Hl$ Hm HPHM8裒H8_^][SUVWH8Hi Hl$ Hm HPHMPsH8_^][LDSUWH0Hi Hl$ Hm HUH (茷HEHtHLy8HLH0_][D #SUVWH8Hi Hl$ Hm HMHtHy9LH8_^][̴SUVWATAUAVAWHHHi0Hl$0Hm0HnHHA_A^A]A\_^][p$SUVWATAUH8Hi Hl$ Hm HU0H '臶HEHtHx8HLH8A]A\_^][SUVWATAUH8Hi Hl$ Hm HU`H &4HEHtHTx8HLH8A]A\_^][SUVWATAUH8Hi Hl$ Hm HMHHtH1x9LH8A]A\_^][SUVWATAUH8Hi Hl$ Hm HMhHtHw9LH8A]A\_^][SUVWATAUH8Hi Hl$ Hm HM8HtHw9LH8A]A\_^][,d+SUVWATAUAVAWHXHi@Hl$@Hm@HMHtHw9LHXA_A^A]A\_^][ؔ4SUWH0Hi Hl$ Hm HHM TH0_][̤?SUVWATH0Hi Hl$ Hm HHM H0A\_^][pdT>SUVWH8Hi Hl$ Hm HMHtHv9LH8_^][,YSUVWATAUH8Hi Hl$ Hm HUH d$׳HEHtHv8HLH8A]A\_^][ؓt_.SUVWATAUH8Hi Hl$ Hm HU H $wHEHtHwv8HLH8A]A\_^][̄TaSUVWATAUAVH0Hi Hl$ Hm H> HM 轍H0A^A]A\_^][@bASUVWATAUAVAWH8Hi Hl$ Hm HtHMXkH8A_A^A]A\_^][SUVWATAUAVAWH8Hi Hl$ Hm H4HM@+H8A_A^A]A\_^][SUVWATAUAVAWH8Hi Hl$ Hm HH "@HEpHtHXu8HLH8A_A^A]A\_^][tdj;SUVWATAUHXHi@Hl$@Hm@HkHXA]A\_^][SUVWATAUHXHi@Hl$@Hm@HM`HtHt9LHXA]A\_^][ 4pSUVWATAUAVAWHHHi0Hl$0Hm0H ~ H(=HHA_A^A]A\_^][̸qSUH8Hi Hl$ Hm H~HHH8][tTrSUVWH8Hi Hl$ Hm H~HH莏H8_^][0sqSUVWATAUHHHi0Hl$0Hm0H~HH:HHA]A\_^][ܐt|SUWH0Hi Hl$ Hm HMHtHDs9LH0_][̘ăSUVWH8Hi Hl$ Hm HUHM6H8_^][dDSUVWH8Hi Hl$ Hm HUHMH8_^][0dSUVWATAUAVAWHHHi0Hl$0Hm0HU`H #HE0HtHr8HLHHA_A^A]A\_^][SUVWATAUAVAWHHHi0Hl$0Hm0HUXH UȮHE8HtHpr8HLHHA_A^A]A\_^][SUVWATAUAVAWHHHi0Hl$0Hm0HMHHtH-r9LHHA_A^A]A\_^][SUVWATAUAVAWHHHi0Hl$0Hm0HHHA_A^A]A\_^][ SUVWATAUAVAWHXHi@Hl$@Hm@HU H pHEHtHq8HLHXA_A^A]A\_^][SUVWATAUAVAWHXHi@Hl$@Hm@HlHXA_A^A]A\_^][̘ԠzSUVWATAUH8Hi Hl$ Hm HMHtHq9LH8A]A\_^][SUVWATAUH8Hi Hl$ Hm HMHtHq9LH8A]A\_^][ ġSUWH0Hi Hl$ Hm HIHMPH0_][SUWH0Hi Hl$ Hm HH 苬HExHtHq8HLH0_][̨4SUVWH8Hi Hl$ Hm H\IHMP苋H8_^][tDSUVWATAUAVH@Hi0Hl$0Hm0HڨH@A^A]A\_^][@dGUH0Hi Hl$ Hm HpH0]UH0Hi Hl$ Hm HE HH95H0]tSUVWH8Hi Hl$ Hm HH8_^][ČTSUVWH8Hi Hl$ Hm HUHM@FH8_^][̐SUWH0Hi Hl$ Hm HUHM0H0_][\PH IApHH hHHHrHdSUVWH8Hi Hl$ Hm HUHM@vH8_^][SUWH0Hi Hl$ Hm HUHM07H0_][̰$~SUVWH8Hi Hl$ Hm HUHM@H8_^][|tSUWH0Hi Hl$ Hm HUHM0跩H0_][HdzSUVWH8Hi Hl$ Hm HUHM@vH8_^][SUWH0Hi Hl$ Hm HUHM07H0_][SUVWATAUH8Hi Hl$ Hm HM0HtHm9LH8A]A\_^][SUVWATAUH8Hi Hl$ Hm HM(HtHOm9LH8A]A\_^][SUVWATAUH8Hi Hl$ Hm HMHtHm9LH8A]A\_^][SUVWATAUH8Hi Hl$ Hm HMHtHl9LH8A]A\_^][SUVWATH0Hi Hl$ Hm HTH0A\_^][̉SUH8Hi Hl$ Hm HH8][̨tSUVWH8Hi Hl$ Hm HUH ;HEHtHSl8HLH8_^][TSUWH0Hi Hl$ Hm HH0_][04 SUH8Hi Hl$ Hm H H8][ $SUVWH8Hi Hl$ Hm HEH\H8_^][؈SUVWATH0Hi Hl$ Hm HEHcH0A\_^][̤dSUH8Hi Hl$ Hm HH8][̀"bSUVWATAUAVH@Hi0Hl$0Hm0H'H@A^A]A\_^][SUVWATAUAVH@Hi0Hl$0Hm0HMHtHj9LH@A^A]A\_^][?SUVWATH0Hi Hl$ Hm HBHM H0A\_^][ԇtCSUWH0Hi Hl$ Hm HUHM07H0_][̠C|SUVWH8Hi Hl$ Hm HUHM@H8_^][lJ>SUVWHHHi0Hl$0Hm0HKHH_^][8$Z|SUVWH8Hi Hl$ Hm HUHM@vH8_^][fNSUVWATAUHX)t$@Hi0Hl$0Hm0HAH~(t$@HXA]A\_^][Dn!SUWH0Hi Hl$ Hm HEH/oH0_][̌4oSUWH0Hi Hl$ Hm HEHoH0_][XoSUH8Hi Hl$ Hm HpH8][4rSUVWATAUH8Hi Hl$ Hm H@HM }H8A]A\_^][TSUWH0Hi Hl$ Hm H;H0_][̅SUVWATH@Hi0Hl$0Hm0H@H}H@A\_^][̈4SUWH0Hi Hl$ Hm HUHM0gH0_][TSUVWATAUAVAWH8Hi Hl$ Hm HM8HtH3g9LH8A_A^A]A\_^][SUVWATAUAVAWH8Hi Hl$ Hm HM0HtHf9LH8A_A^A]A\_^][SUVWATAUAVAWH8Hi Hl$ Hm HM(HtHf9LH8A_A^A]A\_^][̈TSUWH0Hi Hl$ Hm HM HtHdf9LH0_][SUWH0Hi Hl$ Hm HMHtH6f9LH0_][SUWH0Hi Hl$ Hm HH0_][ SUVWATAUAVH0Hi Hl$ Hm H>H0A^A]A\_^][؃ĜSUVWATAUAVAWHHHi0Hl$0Hm0E HhHHA_A^A]A\_^][̔SUWH0Hi Hl$ Hm HH0_][peSUVWATAUHHHi0Hl$0Hm0HHHA]A\_^][SUVWATAUHHHi0Hl$0Hm0HHHA]A\_^][tSUH8Hi Hl$ Hm HUH -HEHtHe8HLH8][ĂySUWH@Hi0Hl$0Hm0EHH@_][̐SUVWATAUAVAWHHHi0Hl$0Hm0HUHH 胞HE(HtHd8HLHHA_A^A]A\_^][SUVWATAUAVAWHHHi0Hl$0Hm0HHH HM03E89A6HE HHHA_A^A]A\_^][؁dSUVWATH0Hi Hl$ Hm HZ;HM axH0A\_^][äsSUVWATAUAVAWH8Hi Hl$ Hm HnH8A_A^A]A\_^][` SUVWATAUAVAWHHHi0Hl$0Hm0H:HM wHHA_A^A]A\_^][SUVWATAUAVAWHHHi0Hl$0Hm0HpH m HE`HtH@c8HLHHA_A^A]A\_^][ȀTS SUVWATAUAVAWHh)t$@)|$PHi0Hl$0Hm0HH:B|Pu4ƅ(H Hy (t$@(|$PHhA_A^A]A\_^][SUVWATAUAVAWHh)t$@)|$PHi0Hl$0Hm0H/ (t$@(|$PHhA_A^A]A\_^][SUVWATAUAVAWHh)t$@)|$PHi0Hl$0Hm0tH9 -(t$@(|$PHhA_A^A]A\_^][SUVWATAUAVAWHh)t$@)|$PHi0Hl$0Hm0H0H CHHtHa8HL(t$@(|$PHhA_A^A]A\_^][SUVWATAUAVAWHh)t$@)|$PHi0Hl$0Hm0H] (t$@(|$PHhA_A^A]A\_^][SUVWATAUAVAWHh)t$@)|$PHi0Hl$0Hm0htH`9+(t$@(|$PHhA_A^A]A\_^][SUVWATAUAVAWHh)t$@)|$PHi0Hl$0Hm0HH:B|Pu2ƅiHH (t$@(|$PHhA_A^A]A\_^][SUVWATAUAVAWHh)t$@)|$PHi0Hl$0Hm0H(t$@(|$PHhA_A^A]A\_^][SUVWATAUAVAWHh)t$@)|$PHi0Hl$0Hm0tH9*(t$@(|$PHhA_A^A]A\_^][SUVWATAUAVAWHh)t$@)|$PHi0Hl$0Hm0HpH HHtH_8HL(t$@(|$PHhA_A^A]A\_^][P}SUWH0Hi Hl$ Hm HUHM0ǘH0_][}SUWH0Hi Hl$ Hm HUHM0臘H0_][|$|SUVWH8Hi Hl$ Hm HUHM@FH8_^][̴|d|SUVWH8Hi Hl$ Hm HUHM@H8_^][̀||SUVWH8Hi Hl$ Hm HUHM@ƗH8_^][L|SUWH0Hi Hl$ Hm HUHM0臗H0_][|!>SUVWATAUHH)t$0Hi Hl$ Hm H4HMPq(t$0HHA]A\_^][{# SUWH0Hi Hl$ Hm H]4HM dqH0_][̠{,SUVWATAUHHHi0Hl$0Hm0H,HHA]A\_^][l{,sSUVWH8Hi Hl$ Hm H,H8_^][8{7zSUVWH8Hi Hl$ Hm HUHM@6H8_^][{T7SUWH0Hi Hl$ Hm HUHM0H0_][zt@bSUVWATAUH8Hi Hl$ Hm HH]03H}8>H z HLHrH/BH8A]A\_^][\zdBSUVWATH0Hi Hl$ Hm HEHBH0A\_^][(zdCSUVWATH0Hi Hl$ Hm HEHCH0A\_^][yDIeH pHH %XHHHjwHҔ̰yISUWH0Hi Hl$ Hm HUHM0gH0_][|yJSUVWH8Hi Hl$ Hm HUHM@&H8_^][HydJSUVWH8Hi Hl$ Hm HMPHtHZ9LH8_^][y$LSUWH0Hi Hl$ Hm HUHM0藓H0_][xtLSUWH0Hi Hl$ Hm HUHM0WH0_][̜x$M|SUVWH8Hi Hl$ Hm HUHM@H8_^][hxdMSUVWH8Hi Hl$ Hm HUHM@֒H8_^][4xMSUVWH8Hi Hl$ Hm H}~NHEHEH HE(HEHE HM(HE 3H;t HMrH8_^][w_SUVWATH0Hi Hl$ Hm HHtHX9LH0A\_^][SUVWATH0Hi Hl$ Hm HHtHX9LH0A\_^][Hw}SUHH)t$0Hi Hl$ Hm EH}(t$0HH][w_UH0Hi Hl$ Hm H7HHMH+H0]vdSUWH0Hi Hl$ Hm HE8fWEH̃H0_][ìvySUVWATAUH8Hi Hl$ Hm HUH 臐HEHtHW8HLH8A]A\_^][XvđSUWH0Hi Hl$ Hm HUHM0gH0_][$v$SUVWH8Hi Hl$ Hm HUHM@&H8_^][u4-SUVWATAUAVAWH8Hi Hl$ Hm HUH 0裏HEHtHV8HLH8A_A^A]A\_^][̌u$SUVWATH0Hi Hl$ Hm HUH 9HEHtHV8HLH0A\_^][8uSUWH0Hi Hl$ Hm HUHM0H0_][u~SUVWH8Hi Hl$ Hm HUHM@֎H8_^][tdSUVWATAUH8Hi Hl$ Hm HU H WHEHtHU8HLH8A]A\_^][|tOSUVWATH0Hi Hl$ Hm H} ~ HMqoH} ~NHEHE蓍H HE0HEHE(HM0HE(3H;t HMfnH0A\_^][sd~SUVWH8Hi Hl$ Hm HUHM@薍H8_^][̴sSUWH0Hi Hl$ Hm HUHM0WH0_][̀sDtUH@)t$0Hi Hl$ Hm fWEH{(t$0H@]LsH 茌HH9nH (s_UH0Hi Hl$ Hm &EHUH yHEH(H0]rcSUWH0Hi Hl$ Hm HM HtHdT9LH0_][SUWH0Hi Hl$ Hm HMHtH6T9LH0_][|rH 茋HH9mH XrTSUWH0Hi Hl$ Hm HUHM0觋H0_][$r~SUVWH8Hi Hl$ Hm HUHM@fH8_^][qt [LH׋kHHkHXq#9SUVWATAUAVAWHHHi0Hl$0Hm0HMp93|Hu&HHA_A^A]A\_^][xqT+SUVWH8Hi Hl$ Hm H+H8_^][Dq3lUH0Hi Hl$ Hm H3H0] q4lUH0Hi Hl$ Hm H?4H0]pJA&lHlHH d藉HHHlH̸p4M1 FlHFlHH GHHHYlHtpM5 kHkHH HHH lHq0pO<H9qp?HH 計HHHkH"oS1kHH _HHHikHوSUVWATH0Hi Hl$ Hm HMHtHyQ9LH0A\_^][̄oT7 kHjHjHH /ʇHLHHjHA0oTU_jHH HHHjHnUf6jH6jHH 7HHHajH豇̸nU^iHiHH THHHjHatnTW+iHH 蟆HHHiH0nXiH">iH>iHH ?HLHH^iH趆m$Y1 6iHhHhHH OHLHH iHa̘m$YhHH 蟅HHHhHSUVWATAUHHHi0Hl$0Hm0HMHtHN9LHHA]A\_^][0m[hVhH hH hHH o HLHH)hH聅ld\`gHH 迄HHHgH9̘l\wfgHfgHH gHHHgHTl^qSUVWHHHi0Hl$0Hm0MfHEHfHH fHHH#gHsH^HH_^][k_fHH 蟃HHHfH̜k`fHH OHHHYfHɃ褃Xk`6fHH \HHH fHyTkaeHH 诂HHHeH)jaeHIeHIeHH JHLHHieHOeHH uHHH"eH蒂mLjaSeHH ,ρHHHdHI$jc5 dHidHidHH jHLHHdH̴igVdHH |HHH)dH虁SUVWATAUAVH0Hi Hl$ Hm McHEHcHH 0ÀHHHcH=HhH0A^A]A\_^][il!cHH oHHHycHhTmHqp迀HH (HHH2cH袀Hp艀HbHH WHHHcHdHEpKHbHH HLHHbH#$hDmHqpHH XHHHbbHHHpHHpHbHH lHLHH&bH~H_HpbHHpRHaHH ~HLHHaH*H HpHHp~H^aHH _~HLHH~aH~HHp~HHp~H aHH p ~HLHH*aH~PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPRP@  rp`P0@ h p`P0@rpP0@ xh p`P0@ h p`P0@  hP0@  hrP@w zw kw ] ] ] ] ] 8_ Q_ (` J` Q` & y` a  : : O9 9 8 8 8 8 y8 y8 r8 O: 8 C\ n\ \ \ \ \ \ 1] [ [ [ 6[ Z Z Z Z FY X X wX oX dX W /W V V U i] ~ ~  ~ i      Z      R  ̀ ڀ ̀  i i i i  i i i 0 i  i   /  > . i. K ȡ % V px ] Add r / / l ̓ ҃ _ t  ƒ . i. y. . ). ). ء . .  / H/ yR/ ) ) yy. . i. . W. kBo i*!-{aX i p 8   \  p n   ?  /    n  i i   " =- =- [- B- B-   . Q     ` `  ʺʺʺ ʺʺʺ").yy-?)$W-K(  {y"A :ARu8 AzaϾANAleX?H J 6 '    J j  " # # G # # # h% & L' X ) * '* # # " & - :     J       :  :   u m U E  h ]    O y ! ( l j _ B I Q y v v v v … yՅ / x a i s i s i i i ކ Ԇ i 0 E b "     i  i  i  Ȣ آ   (  i 8 i X Q X px b i i ʌ i ڌ ڌ   y 7  H i  i  + A ܎ y i l i ҏ i 6 i X i  > > v v v v W W d q   l 7 -w v \ a h D y) -  l  A vA eA ZA A @ j@ ? C ]? ? A = = A B x ǒ ) k 5  G M _ x q x  i i i 6 6 . . N  % G B = B = B = 8 3 x x x 'HW "  ! ! px + ȣ أ   ( 8 H X h x Ȥ ؤ   ( 8 H v X h x ȥ إ   ( 8 H X h Ȧ ئ   ( 8 H X h x ȧ ا   ( 8 H X h `s l X b b b b b b b b b b b b b b b b    ֘ ݘ   y  = = = = = = ʠ T J = = = 1 ; , = = ԳAAAFMee ب ,D"/rl[7b6SY^  (  - z- z- z- )- y    Z       f @   u   8 ! H - )    " h" 3" "" G" ^xySqysX h ABx r + * + y7 7 g7 7 6 y7 6 y7 A6 8  o7 ȩ ة G . i. . i. x x x x yy y )- q q y y z { r{ { { z z {z ry ry Aq q { i  y{ | { - - } } #} | yi i q  G G q q   q r (r r r r r )s 8s - - G G } Y} s} } } Ns Us Ns Us Ns Us v v v v Q} Q} ;} 3}  $., C, <, , m, , , , 2, 2,  + 1 1 H0 =0 80 .0 $0 0 / / / / / l 5 5 5 5 5 4 4 2 2 5  t~ \~ 1 1 1 1 1 x px wx ~x ( bb mb b d= M= < < < < < < < z< =< (< < ; : r: : @= 8 u= ; ;  = = O9 = 9 = > > > }> 5> ? Us Ns Us Ns - - - - `s ks H G G }s s s s Ut t t t t x G F F )F F - - - X QG - - jG M 8M M N N N O 7O WO hO O VP P P P P P AYQ Q R BS TS \S S h T T T 'U ;U HU ]U U U L L K K >K #K K K J ~J 5J J I I I yI ]I I H x G G G 5 H %H 4w >w Tw `s Gv v v `s Gv v v v v v v v v `s Gv -w v v v v v Us %v Us Ns ':B;$ijD#y'jFB"  jG)!:bJ" )J# +94 GS FS FS 3! # \ E9."NR&FI# f9ezCI`IFjB~@|֥._8J2B)gEI=/up_3aiC%"Z' MD]DyX)Zt&iE{l="% ' EXy-n( Y{L~O("'z&ZE9"K\R!J)Z% y9Z%K\R!* [sS /73yz)S쳑20 Z SESۢL0ak " E& ZmD%ZOD_B 9 Y*D$yDyayA FIcyCI`IF)DIaIG)EIby@@ %:D &y`~fk#DIa* Z[,T# B:Dzf *yzB!![>\M"#'y'ExbDy!]E+By' i#[>~+/3ŰO9S x3 )SЖ2).)Sx2Z\7 vSKk Sɰ[ Sɰ\z Sɐj Sɠ^5˖5h[YS<S[ iSGiS6 lDS̰O4 xFS̰k5TS쐍j5l1A"'ZZIJ#L-t=%Z>! $ ` d ` d `$ZB9$k^` ZF9#^k^ƐM7 vS i7x0Š ˖0j S n4"[RJRZB#y# y}DB>@!y@ %yf~bk'GIdy# yJ; |M>"%!Z!j@)%y[ԑ(Y]96‘!9yy)#`Ja<\T  #L)Ң&IK&XJy-#* ":|4 4 @SYI-#>+4 ʔ@SYI-#]+M4 @SyI-#y Գ" k4 @SW;6b EzD*,@-rm!$ BIG;|]>&% CJa G % D*+J+4#\;r[@y]& yR#9B9YJD& " & bJ 00@ S I#y*@" lI 0A#$;J´gjN#9#i# "i&X Sˠї1# *1A#)YC"$B!#A )/R@xr!f4AY C49)#II@Y4by #ID9BYDY)2&j }]C*G*$Z>JV%I{$ |E'9~fX"' "*@*+' { C˰| Cˠ )`Uy#ii&L< y}RF bEIByGLCI`LD!o8J{\R#y":fC:e=Gyd+&iaidLAIfLCI`LEIbLGIdLAIfLCI`LEIbLGIdLAIfiC Gyd[,vGCy`_đAyiv:ĔGyLƔ@^BLhc ĔDyFL.giOĔ@yYv*ĔFy"%J&( )j" !\ez%9C+8AZG }d9/Biy&! {e' ]BNB)D' YBY '9\C)Fy?Ayh yD9$i,DL"l'j~F "hAYirZ%z&*[%J&( R%*:[(&y ^4 4 ϗ4YIS _2Š 2 ϧ2Ő2Őz*S :SO:S|:S3 0y SʳJ SH Sy_S 1 | S Sx0 | Sɐj Sɰš0 )ڕ22_1lS¡1j4 JSБ\4O4|4/4{WS TS WSy5 |#@yYGIK"$ $'RoX)D#:@*[,D$&z'+D+ $ e{=>&% !Y$ ; zG!;{|}^D yG '({B&iE{"!*"k'ZF""&y&zD!#Z$|=mT"i#+lD!9!'ZF9 *j;{(h*jZ0,0 0ɰY S 2 2Őɠ)S Ԑ3 ܕ3@9S 3z2̰l*S2m3 {:SܰmJSɠ4 $^bn&b"zGj^D& {ĕlR%y&ZEx"! "jkl~m^D'(yjD [$I! $j#y#8R%zD,#;D #l'("$:% m/t&#ZB=!9$iCY"'z YDln/O8X"'I#*#I'["lf*'&K8Ɨbi'IZcK~m!Z %': RK$y=t]'*%ZIDi" $yKG -A NC%'* %ZKDk" $yM"!J"j[HYR!*y'I#yyy $*y $yy $y_k Sɐɠ_ Sɐ Sɠy SɠY S)7N`SI7 i+Sʐɠ_+Sʐ2 h[Sɠ_[S[Sy[Sꠌ*[S.͗2 2 222 2?jS6 j S˰0 ڗ6;6 6J1 Sİ1k3 3 3 ^ ;Sϧ( S̠: S̠뒣0 .٦1|11xɲ4KS°4*kSɐ*kSð6 7 i {S/4ɠ_44y4Y4SS US QS WS SS US M0 J['zM%'k$*${lM.b":dYC %YD F Gr#+%/( jR!9# !I`Igz$zE*zkV&  YC ِ5YC {YC ~YC4 ɐ ICɑ4 ݠ4 k/9Cɐ ِ3 *9Cٗ( / ;p!IiIIݰw u|IY #@IY! #*9#z!YWp,Y5# [b Na=Cy`}Byg Ay+)5ңEy+Dy֗8 ֐+9# #~ap9 #9)# z)0b E' [B$)#9I#Zk0a@!I\BB$N)9i:D$=dLAIfYA "{@k"! FҳJT$GJgOH)Z+T%@JgO8)b%I% F ^R #hD zEy \M>D%~x k<=>/D$ihD `#i+"* G ">$ :m␙ yґ`mc<`9 di<#&nDMi% ;F+]Ҕ#.8Ɨ@j C*- MƐEy*E*LR @<ZiҶ@[>$ *iHiS z6Ő JS٥ٖ12ߗ23 3 lܤ0)0)|3 m:SФBS,^6[4AZiDy" *{R,@ymDB.$Z/DOBoJ"ohR"*"Jb)ZohR"*9K3 ;9S 32Š [)S 2Ű92h)S "S1n1{ I3"iDy+& l@9@ p=6$i*#\C%I>t/R@;xnj)1$*DJB!G&) 9&9]D# ')y'y,2lEcpz}2$ d-DM` /t'*cZRC,mV nt%Za9RA L&&+"I"zFY!GR%{\t#MRB_H9+l]*r0ݔt0Uej% 9!Z[a }D  !LFIcygF 'ycB # BYBIGy"LGIdBy!@|! @Y@IEy LEIb@y'F|' FYFICi&LCI`Fy%jD/% DYDIAIFA* LEIb:f Dz,m>D%*Hė%L*gy”@IX̔hy#I9GiKAImCI`LEIbLGIdLAIfLCI`LEIbLGIdiA Eybxı: vEAyf>ıHvALEybLFc@LDyaFLBygDL@yeiBLFyc JvFLBygDL@ye AfBgC`ELf+I0#9Jr;"KrA Hi #I% ; )6AIJ#I,!ib~K C4"Y ġe< $,b""Z jG)!8"##>B#+>)Q SH0 퐓0 0 D S4ESj@S k484(3R&9IDy!zR+rKbkD&#Z>A'9 9R' "{|r#}R$ ':d@ie \D&y&ZE9"O)2$ y "OI3=J6ŠeS cS dS RiS]iS@iS϶6l5Δ5@YS:7R&#\ZD! 0:7R&#ZD!L 09Y# ;$Ydp* 1#% E;kR yR>B^'joD (*"" *bJ" J00@ S^z`¦A#:k$'!#9D>"^"~f*$ & "%zBIz#K7A#)YR:%*k E9-G*^R/G$f)ґZ[lD M.^)iTCZaP[;5A#IY'DiD+"K#nG "Z@("$'y&!9%))Z$'y j5 I5ORS WS wS ʰvS wS qS n0A9y{BybG,[%z= OD# G:%zC%{lR!* YF9%y'_hĢIJ+{=D"F$zC%y R$Ji'J&y R$*y ~S ɰ*S }9S ]9S *9S R Sɰj S[ S2j)S۴2KCSː @Sˠ)5ɰ_5Y9Y#9BY$aCbC,1”%z*'{FyE&8"& iZĒ;–|f%%y 'H9" Yi!$yy&(;4Ű GS `4|[4| 7–':;!+ e NAYo iB ;!y#y "J+BK"٧M-X#iD)'ZZDjB L`nC% hĒIZD'{l]}"!J"ohIģ:k" #Iz!J"o <[MS ɐ]S YS ͠_S N IS ɐ]IS YIS ͐hIS |IS W)Sɐ])SY)SͰh)Sz;)SJ7Y7͐N7P9S 3 ͐h9S3 [5 ɐ]5 Y5 ͠_5 jfSː eS˰ eS eS*J0R E9* E9,! &]e!'z%z#Eid%}MXD`iL2 'Ik C#)4#% 5A#%iZR " GIMCIH <T#~R"z IS4 ^4 YS}5 ^˗5 iShiS:iS7 7^70 0 ^0 1 1 ^1 ٠2 l*Sh*S+J:S안3tSASS4 FS͐앉GS͠CSͰu4 + I!9 D#tFj;B[b@"dpbpy # 9RyFK":Y 1b &: IJ&{. g:K #l r*C {'\]D}E;?("$)#R&;=?9j¦<-B%I$ C_Ҳ9*; D#m^D'O"&-$;% ! &KR&ri"oI*4吨(IS3 9Sx3 Ϡj9SВZ5 5D5XYS[YS_iSʐZiSʰ44i4 4GSkY2¦ *GD% M"'_i5:#ZiDyB# k|D&y_B#n >o7[7 7=tS qS '6Š 96ŰxdS 5@[YI-#+ 4 @S9)#9GYɐ,6!;$J#y#'"y'n I#J#z&:#9#:$<#,')X'I#m/V!9 c#i*"K|" ~ 00 0ѕ#yI=#* ķ" ),[4@S{Y0@YBzDIf$EyYi#!p*IR91"YZDzDyDJFB{#T#llD C% _ &F:b%+T% # #([5 Y;&%ZM%h':@ #^_XR'Z$YClR!N^?D&*DijY]lYC =YC)C鰓zC =i0ҐX i0ÓOi0*9 pXYJ ")g:,E96!zi* 0@IYT kFH{#cb')id[k!Fi=D]"}'-G D"L OD zEnOD& § \~8D%y!Z@9"K b%.~D!#Z#ZG<}nD /ohY&)Z$ y9Z$ y9Z#/o9)S +)S 7N3听3gISIS4;*4AS>5 7 ]9J;?l 7@!Fi:DJbj%yLR|# /xD!9iZ9iQS z5)0Ő 0Űo; S :4 ;4 9p# E Zt DVmv9`#[)GyJDjC9 bGi  #@yyy9% :TZBz" 7@ JaF-g ?ƑIjĔ,|Ƒ>ơHvFICjKF#\nԣ´H;M2R)" [&{"GiO d" ` Fٗ^t&9D#Z MB'yBMb&;EZ!Z@)"$ Z% Iz% yYz$ yl0ȵ0+1 1Őɱ1Š4 >4R)" [&{"GiO d" ` # A9&iCLGydĤZ+vGLCy` f B gK=Ĵ~OV&9A)I:<( )"$'y$If+i$'y 7j7uS @SʐءASʐm4 K92B)D) BkN#jEYFk 4#z&I!z}$IhIz[R 9Fb"+G^D&ID;& 2#)#jr!L>o""I#;"jA<"%J #jB)$oIykr#&I"Ie9%J D"Ib '& * D"AO("yz% Yz& װ,IS 4]6 7KFS BS͐p4 ۥk0B#&'I_yđ ,mD")'zFl$ A/X9 XB +ĥ .R&IGydh*4$ lR"ib"zA#XiR"ZA;"IAIGID"zA&R%*% YF9%y%\"'ZF\%IEJ!Z@*"$ %"*[%J&*R%*:[$J%22*S ?:S Ȣ3Ő 5?ZSn S[ S =S{Sn0 Ȧ0  S_2;9Sy˧1 nS?JSʠġ4 bS 6,qS{7 m*6A I$ {#zDN kA)n_BZ7ZcC*i9YBKAMnJZB#%ZK! MAyo& LEZ"Z@9"K{K{R7}7vS wS -)#9D9rY#&9Kt{r#I#%y^(D$hR C;%z{mi .?"% #i&jE)'|b)Z% 9Z! 7 ˤ<7 #7 n7 +5 ɰUSxQSTS VS<`Rr9"9 D;'O':B:#lA<"%Z% %i'8 £zD!;{|>/?IFIz#'y2i5Ő5ŰPSN5:+7 NqS?6R& )$y/BKRkE<=Ai/iORoXx"! "jkr#y#mr )#/A8B%Z%yd Ң|D!=}~HFIz!J"j=}jl4;IS 4Y79rS Y7Ő<ڒ3 l9SM;9S$YS 5?;YSAS;4*4q4jZ5 .SS RSJ5 )5 ~5 Y4Bz#Z1 $ +&;~FIy>0R& zYDi#y@#%ZL"J~Fdh:+K"& '=> t"$Z$*$BMNF& %bz"ZA9#[bi&J'=[Y Y)S N22PYS N5ŐyeSXIS4/ S0 kiSɖ6 [iSɐlL1A#%z'"$KB9R& #%y%\R'ZF,%yD*%9*J"& '<=rIz&J'<*z7x,7wS ˰;7 [7gS eS yiSǒ6ɗ6 ˑ6 ,iS۰:)S2Y)SJڕ5 5 M;YS-3El:A#$,R\C&' G;"?8IB&y jG"# !Mb%kDɡk2"8r/'K,myJkb ;&rIk#Mm?>_N#JY7@ YҵA-)#9D9rY#&9Kt{r#I#%y^(D$hR C;%z{mi .?"% #i&jE)'|b)Z% 9Z! 6 ˤ<6 #6 n6 +4ɰESxASDS FS+95" jEI,@9]D}B?,| 5" jD9D/hYIJ^R JEj$A:+l=.2?lI 0z`1` YO=+3R&9ITyrFIk%& Zl$I>A#% $xibJ_HR'* ;J S ~ S ; S US h5Ő]rS{7 79 Y#;)¶d`0a0KS'z|$&zo9R%z%" $z$!?8 R#*+lDY '-n_(2 V:u`Pu`UMr`p`M*0F J "I $*mA;"%!y!^6:ٔ2<)S | P!"i`!igxi&'if9 %z 9p²'!#%'!#}"r$#%$(R4f4Ai C.2A#$AIzF ZM9?ĕx4 l!{“n" ?"%""X"') T" t&C#[!&I!+AEA$y!l&zAlD<" "%b' [# S.ٖ0 s S̠S.1#,:Yj)1R& Iy$Jk }2906"M:# ! DY!Y TKr\T|@$JO$_2! D"`8x9j5by:!")`i& )g f9ejre d9cMrc b99:`p*Yp²#%'!#'@''&%$*Yp´%'!#%!@'&%%$i)'L";"[! '&%"i)',z"";  '$#"i)'#& ""&"&*Yp²#%'!#' '$#%!Z) #R#')Z2'#B)Ryi#u' Z"44R'Ih42&vryb E&I[bf^t/gF9 ZD&: yF 2"ZA,'A 'ZF "" #|}?hD %Z%* #zA &K@ %JbJgZgyB zEx*t$ !Z@,\> B#%zD,#Z l$I&zE'.R&Z&"IcYJ[="Z& J$i G!#*O•"ZD:"Z!y^!kmE9/"O Z '+D^R?xT!yKRBi yCO^b&:NI #e#^{2P;0CJҴG MCyg*%IC%KlVDyFRG:B['IEyGR@ "(`p)Y6%yJc{@/Xf'j@"M P/ P 0! G KaI g9neX)y H- 3!y G KaImFCy`ID aI`&^nJ5"=%KX& n4&Y”[R!Ja:&_fJDIa: %I0ʐ0I1 ʐ(C9C 1 I2 I30i;93A I#=+$94/j5"=#J4-2”Xr%Je:&_fJDIa `yJ! I0\ CzC9)C̠ 9)C̰x2 X)C̐^,*6A"kI#ZD;$Z.DN"n!*[n!y+YS Ǒ5Š0 Z^SՖ2Z|9So)+7!x2@'Z E'%",@ ^6"?R#x2@*B%:C [G'Yʐ;Y.Z5A#% :"I C))=$MB*R?B_D%9KL 4R& jJRzEYI<$LByR>B^h;6R& =D;r[$'!j^RFYiDX9T%:KRBI NNT"{6"% 9A9zE 0 )`#:y"jk!I eNppZ)1R& I:4JRzBeQעcpl6q"y 'E+MDmRN"yExzKR%:#yFHD&IZ$ j-T" @i%Cz"J@I%CKL 1R& IJRzB #%IMaiH 6Q(tp| 1R& IJRzB #% @I_H K6TXqpڢ_1" 'I]@!i@ %yCCZ;D%yDIay@IeyDI!$IB$I&iE{l=T# A:CK%y*b":'; *&I"k =A9`-_XR&"k ]A9`.XY")Z'"y;S x S o S ^ j1R& I:4JRzreI=@"I&YA9z,D$i YdT{ i1R& IJRzB #% E9bQ(lK5R& IJRzr # \aIeid9`YdIG_(YD'jCI 9g C9`8up: =#er $'  #%M`IH >D%AI&yA;}N:B!8)IJ R#Zgi IGIdIC zG!:KR * +$i'yG $ZE*$#)AyFIEjByg f9eIDlRFY#yBORDy!y@* [D' FMA hc j;!]$?' 9zD’${bXBjf:,8i" ri%!y)Y4M4(5 5 TS.2 9Sꐪ3(nISݱ4J# #9#)dCi  Iz& q} CY #IiD{B  IY1!9yD²&I\R (A("$9#L~" ;!$y;#'y1ʵ1)S {)S z)6$ :;$ :>C)9<# :%ii3x  3’F| [#KkI6•F E9+!+%;@ZrۣIF>+$&K D'ine9dIC]FICi@,R'ZF}^(A:#J&%y#y 8R ZG,&"="Y&B' y 2#[m^Oo" J!YoXD'IR!;!i!y"I$IC9@*;"%y&-T#/HD&IEy$| "*[!J"mIZR!*i]lS KS ^k:S 33Š~0ġ0 2*S0l Sɖ00M Sʶo)#cb9!IzD&y\"|B%*AIF9CY{MMB$Y!z@,&$;'i&y%I&ID9A>/"$y$ yT!@:E9BL=)Ir&?E"M^R!*!M^R!*:[$796(iS? S+0E'yD;E9|&?%$}`o)yD! L4G K":& *$K0 >0 ܗ1 2 Yy0E' D;"OXIcZ'Llh#K C̠}CݢlFB$|% !:~ Y*k<-}N/t$J{R&ZEmr#:C)%'* {$m~"#I'*'y"[B)$k|?8)D$iM+M>""I&* &ZE9"z%<-Nn" y!y!@*"$:";$ #IEk'!y)Cj;B$&JN& X2◩# KҐ"YD>"^#zY"yz#I'yYz&I"yYz"I&yYz'I#yYz$:Yzl%)RiS 6 6 ە6 6 \kiSȐKyS͐HyS͐]yS͠ySͰͶ7 ?7tS퐬j7wS퐹’00(0 0~0 0  S۰0 h٦1 |kS #K9A Jc*)3#K I|'j_Yk5F'!* 'Z\D|"$y>F' Ґy E9'K!MK80/[ S %S jS 1Űy5 L#z tG= "*A:+A#I=!jD/"O) t"$9$:$iC]"': O$ )J'z OX2 5(SO;Sx4 4R 9#Iԓ"$ :$jKCz G!#JYZ>=*3a&}r;@y|R-&hҗB# @y'+(K i)0P)0ܑ 9#Yi$'LLQ`=6# iRy':/#Y&:A+ lMē.6# yZ;,Km^_;h h R$ZNkr֢CS̐X94 4 [6cS>gS 4#7[9i2RRI"'!Z%p*ASDS.*"|y%--fLCI LEI"|Dya|Cy` &LCz'\8apepI4#" 9 #i #Z2! ZbI\D|'Y)#LydaKYG J%Y=&Z+֔n֤Y*b ].Ĥo8iҳ \>8y#yz)7$i԰Ey,v|CyF91b &iZDzEI<@!`0##49I# I6a"JjBF:.F+i+dFybIF,bIE{M_ D"F {i2R& y:DZBz"D& .# yKI6A#%z:& LDl#I/\ 0R& )C$! R=!yg'PS J4FS )#I9'I{CYyI=#Z ԰" ),4@SYI-#>+m4 ʑ@Si # IzI4#yz$ "9J#i Z I#I)!%* I#$yҶCI#i 9#T;NJ4F bj$i<&*>Ē9ZR Y Mrd[aI!zEY: C #)9"*rnj$ji% i # T]C9FR"{&B#jBKB&#ly3#"+F: F{D" @)?xҒkѕ ` # Y #9%Bz: 0#;9µ'NBnB"#2L C ,Y3@yi"O^KO8D%+Ei#[MrI6b EK:4  #@Z 4b 4Az[ 2B% #i*D:"ZR A&"& "RNR~B"?Bo" G DiB:B%#Z#&B"ZA9B%I#YB#J%!y Ԓ1[S 1;1 S $ S 0Š~0Y6"j 9{2E*: RA9Z;,RG9$ (xIirC ,tG:Anԡ'j,GIMA4LF 4@:?z2"D&9 &I]R.' #9%9ByGrF<]tB:D96DY 0b EJ*ĵF']FٗZ4& #Olnm;ӱ+n: 2 ={D[- M46#y '<_R ZMN?hIR' Byo)vigj,'Y e`O:f`e#" Y#ҠFy;@Iki#Y)AIjYI#9" B;90#j#i=#?—9D%A;2cZZ# {e&y89jĕ[ mXi¤ZKF''B si3#Ij$'NN"x'O4 :TS鐗O6: 3#ijı%9 $ )2FKJR Bz-' n 4qB R;A$)=f.‘"!Y`", P<7FJRzE !#JbAIf{bDIa-bGId^bBIghV'I&%)cJr)a)jp6^:7aYJF*LFLB !LF9cL@9e ai|¦mhPP[Y0R'&L"\ ! O"_&`I4R&Yy'9S;7@ZA lC&.DyaIFLBygM_ƥyJơ \ơnְ Yְ{(?=1# E yLV\" _T \aYdy`OY #9F!y,0&I#Im"=E 'Y#yA+R$ZB ;'EIB 'ZE9'R%*%BIG %:)Z!J!Z,S S ϳ0Šn4 <i0#j# !$ $ $y&)eMBQ[7@ZA lC&.DyaIFLBygM_ƥyJơ \ơnO·: Ʒ-(?Li1$Iz%!i'|BHyJ: 1#Ij$'i\^j3r9bIG [2 "!,Dy&CI@ &,b#9"rIrS Y # E + J#9F[@-9 #9%  #Y9%\Fz #9 )1&zBK RM$,O 4Fk1akZ"*lbyo)Z+֓MHKNƵ9 ְ,|ƴo)y+{94#jZ1FKJR ' MA yI# &#"): 1fjf }fy;93FKJ ,"}!L ;+I4R'Y* #idLc"'Y = 5aiJF*LF[_”)y;(`ici!\ zXUPZ6cyjF I?ĕ(Y:[\->”/F$$G)jJ3B)BB .r#A(B!*@*XxrK0 0x4ɰBS 9#¤Fy;#)Up-9*2!Ljc [CI D"G!k@iIzM&~ 6_4 #"Y@I[M*0'L{"B B-BB —mF%O'2+6#ybj$ir9c~"!z! YC!$L% @y] vieJґ}&Ғ<| 0)Z3aYJ¶fc)m@:o ĔKĔ ĔNĤԧx¤J\(bYe)+aPkiLy3#Ij$'NN"x+'O4 :TS鐗O6R>0@ )`9ZB {rLtC@:Bxđ;K{|xfDy"iA;}?(xIirC ,tG:AnĖ}^/D$tF+@[|tD:F/o/7¤#&!$,}" ")!8)b% ‘<"%)$m^2')&pK I|MCǔ2 `CdC0/7 ɐN Y&9"9!9%9l 7a9iC Z% EB;Nt8t@B+hQP;5"Y[!:^ByHIrAj tE:GNoġ V!itC+E,MtA:C #[yyI#[y&c"J i2R Ey*DJrtk@E:~tOh9I#[ygYZ)0#u&,K"[d% &p̐ #cb''?"KYĔ$I[!Z}“!)hC Yb*dzAFJd^G!& K$' ;Jr ; $y=iS J{iS y#''LlR|bM" o9 Z+,rGMntC:E)JkV'LtA+C(tG:AcY#9'9d?B"Z£\-}NrAo tE:GKlıV$ b|m?H*LmrE/DAJ:t BM' k i>yY X9ȦN9m6A# &KAIlCi^CZ'FL? k^?z(%)C @ Ey# AGZ;' ECbGyD Ay'9&DA= Iq`J90uG!K\R 'yµaCUC#Iy9;#Y'KzD!:qCbC[1ҒF:!{B,F*OҖyZ+,~Ҧ R#_#mEJ$yҶ R#_#_"jOz;HpY6r&c$Z1A$AyzF9|rpJ 1"ik&I]gy5b &iZDzs09I#99"Y #tbR  #*yf#"  6")r '&Mb*xIr#Z B#y#)C; '9#jB)$jL~_j(4 ˠl4 )4R)RY  P#R%*DJ"j2r 1-+*5B'#jAj;C%)]E'92#b ! 0dPڧeP{QpTp-vz)0")r '&Mb)Y-#]+|4 4 @Sy=#* Ĵ"), 4 4@S )R!mZGyMGydXrc,T% l$~ƔH֖J+; Fch9[,V#n?O Gyd% ]mN±IKQi Z 2F/2_|ِȐ 0I4R& yi$)KbLbbBm" #y)"%I S095G~})5GmCy  ICY]{*6"YbJB FI:5$# \' ^cE' Aif*$lgi'<%~DY$ =<"9##-"H')"i! $}/ҵ9:L"'=NR I xKD&xi l % %LByG& 'J'yN!$#Z̠|-:>ɠ9+ɐy)PMk '\bPb(b zbJ!! : r Y rӒ! ː H! mj6!Jy!Zlx%zAI%IAI%+& @+LB$YJO'ّ j bB bkYY2AIy&*K"%k>%y?T_",9bI' ZA_AO& Y:B' "m".$kEoR!ɢR$"9#i#XҶ D!GL!roHR')'9]q*)xI ][bK.DN$l%JJ07 Ǒ*)xI ][bK.DN$<%ZJ07 Y$Y ҵdKMDm 0+7 9 #I9¢$Zq0{0R& yi$' +RKB9 R=& n$' "H” :j2 %y!bJ$ ' 3Ė3*[9S Ǒ3 ^9S %9S Б3Y9S  0R& yi$' R;A9|R-$& N"% "! Gy% *"$ B |bJ# %PS LlS 1~S ʰ1h1{1\j22&v¤#Ij" $J]"}BN# #"4 @4 yWS Z5)Е"Lz# lD D %JkCɐ+ C٠|)pkY2"&yJ"& L"& N"Y #g& i#i)A ;4"%y9!J$~,DuRtRy9 #"YiF!JeCUC- #*AlE&!"*@|"HIJ D"L.x¤I*|^X+\MO*^/"y#L\wSl4_5* 1' kT Gi#9 # $ : 2$j %$ ;96$yjb GLNcmd9sp<i5#I:#Ze'9# A<}& *i#I9#i{7" $^< y}Ey?BoX9D%y&yE{b! @:"I@:Y#c\]NnR $y$h)*"$ :*[ $y:[&"y:[$ yy9iS ܕ6 ]iS6 ,iS |)S ܕ2 ])Sɐ鰖2 +)S)7]yS鐉Е77*ySm:QD&yJTjRKA#i#I"izk"!# ![AIfiage'nV`@ IT`~{ dp"/;KI6R& i *nD&*Kh `p+5E&9G:["{" MBF&^E 'KBē.£8R"hB X1@S0kS@*³f +t~“8&%x,“m& 5""@J& Ez"L!yG ,£m& n_2nO |ȴIilZy5b &iZDzA0\#y'!#*+2kB,@=G $*BIG* kL-}rEyB 'IEyCYJ+D$j ]&IDycX9'!IG|M.ahR $y$"# ;""I@yFn? Izr*[# ʢ99S@9S3y5b &iZDzB0z)P#@yiE'=@I^F0 *0R)@yZ#I4l$ "bmAIo"#rM*1!) G!*{D' ]#IGxI2kz#$y+T[" b ym& ")"yBIJ {D!LĔnR$YR&z2"[R"Y$ Ig(T#*zk<ҵo" AIf Z lB$9D !"i$r5x9 #i)DI2Ayi4:DZR;!#y-2#+/I*kL^/xD!]-``RpPp 91"* &D'IO2 J (Tp< 1B'!yF "*B"\$ $Z/I+cpNh],y7@yYDy2ZD r[t,DAJ?t@B+ 4R)z)P# E :b &i\D|B0]JJ7!yyD "*@lk$Z-DM"m% J :m% *H7M6ŰIz6D{zy3B%)9 [L"=rDNR/bJ|Bry)S JbS0 InS;91!KaZ^f/(R&y& k: 0AyJ#|]bL)4$#Y{Y6FJ>A&yK#y#*D?i <$)X2@!y%'y[D{!z &:NbF “j[{"! "mnoH9;|R$)#IAOr&I:2& B&=.xR#z@ !!#y yC_XR'YbYeI%:'>#9dI M>R%-R&*:[#K' "jN77ϷLyS)ySpySDySkS 1 uS qSX;7n7 y7U S 0 J SА.4ʰ 4CS|FSp4IGSz)!*&|m"}#$ &0#:rZ&|&i]D}E'EyBHr& &y# F >B'yD!Id &I" E;' }n"" Y 9% @' "I%-$ 'I"I&/)VS 5PSUSSSDSː@S˰ 4 @SFS;92#% J!$z$L'yL5 }0”D%IJAJkDy-!#*'mFɔ=#o"#_"-!+ l&:d]@:e<" IflBIg[$j$$ #y#I#<@;` &IdJ'Ig$*c)*[! mSДTSbSΰЖ0Z3a)'F[NCJ{ #'9*"J"i#*\G^D/•8XY2# "Y"I% C@K"Y# E*$ B#JBA%)) C iI)P_ p9 p޳ p<9-̑yi%L0@ 9#YzB \ay~%(:+KRCy@ #)# #IBH ҥk\MV%ygIE ´K<}HCʗ10 ;,ipx\ip<i1A Ib'ikD B[i: # 9! #9ybJ"+|[I5!$9 b[#i=ƕx:2##: 5$ kc\^b[]2B Y%|& /4hj,֓NƤ9 0' r{Bl"|rsL:i6"! z$:\@;^$y###M Cː_C됒I)CLi3ңEy+Alm!K fxYT' EI:#T9AIjҰ$jM[fYDJA +&fD AI Z&fCY`)FI%yd+"b?GYd)B !+'g?DYa)G*&+$d?AYfI km?fFYCY"+ `?EYbXI*,}NfBYGYh$KAYmfNAYgI> * P#@yiE )kƓr044¢B zB,@<~#-@;EbjBygMҒo8: V"-G;DajAy&{#<"<' $Z# '9%+E ")!) :D !I$NAnF+cyGKd]AFjcyGJd9!NFnC+`yDKa]FCj`yDJa)&N8䖘@+YAKk֕Ceyf#):!:\"I]Bndy e],đGjM@J_V(┛GnJay\b]~đDjEJ*$NF+=GKO֕Aicy{$:]f|8b 'lKAZlt R]&KFziC%yL& yBjF "J ҡE:MFmE9 r/"O%!JZnf[)$zXR<*z:S鐝ק2=2/]7=>7ʒ1 1 MShS Sݓ0 n[6 mO5SSTSȐVSUSMo+S?+Sߴ2 +Sʠk+Sб2oʱ0ʠk S  S L S >MjS 6@S CS M4ȐGS GS [49#J*fZ$AyzF!9']Xv0MIMI#Z#*j 45 57-3ҒF:!{BlE bY@*&mAG:$ $ҦK,|}HҶj[R 8ij=.H9R&&m@J'/)R$/ [+ *>mYM4q&:L K%9!A#jd\^t$jeilԤmV (iµ2#' B[!^(i ,}4!z ZfCj!@IEy$ $)ٶ1ْ\ C- C\0 0 Li0Lki0 >YpY})j5!KaZ^f/(kݗ0$$+TKBI|'O&Y&9F*#I$IGK&#o L& F #iAig^/xrE)Bi@i'<=&%y%-EyBG:;&%y% ) 9'EZB;@;'FIDI#*c/xy[,^8 j;lM>AYhƐD)GYLB a&9hD GkkEI="*/fGIif|La ~d )g [b) EZ>" e ;`)lCZ * B!Gij%I>iC+͔5 5 ړ1X9CY)CУ+ C<7 )} P~yp 4b~jZ1fyz°&Cy@ >'KGr%BIG %&$٧"&$h"n&&9/ (A9i" !%*M%9MR<|:kbc\r'K|"m. R%*K|:rK|z# K| p+%b%'K|.rK|n" K| !%*ْn5?ZS)7 7 =zS7 YzS?zS6 ?jS}ʡ4 ?JS͐Lڤ33 =:S3 Y:S?:Sx5 5 5 )5 MiS?iSΐ6 ˣ2ʗ S9 S0n? S0 Y S? Sz Sm1 1 =S1 _?S1 YS?S0 0 =Sϰ0 YS?SϰH^.S2NS444ɐ4NSMNSqSsS =7谍uS Y7?7mi S1L2蒹2j)S 11ɠ S = S [ S Y S 0ʠߧ1갸8SO1갬г1갍1ɐ1?S[?;S{33ɔ~KS zL[S*[[S* Y[S*ڷ5̱6kS JkS 6[kS n3˰3ɐ3>S 3ФPS SS =5US Y5?5)2ByKA lE H #iI#M $ Lc.`GndCy k<=)1b ƵGnL`IX QҤa[z8'\FNC;A9G9E9C\@yFC!YGiE8B'IF:D%R@JfzEyG ]5 ޥSC(TC^*lKh{\`  #`z$)  #)@"  4A#9Zc)I$)/&?ii"%I}*2$#l&zNI”|&!IG~_r$YI#ID9!Ii|#b ," ^E *#o #i #i9Y#Ly! # L i3J) @m_&oI:R'*&L"*LEPD/m+ 9`#"zD.!yz&*LS0P0Z1#IĢ'"${]9#I9´EZ, y}fz_Đ(ƔyJ;2&{\=2&}^~"!y!|%jDj" J&z% l4|PS>Z1"%&IJ"y !#y=g #jBIB& $ili7#L[" 'nh@ّ[(bLGIdM}upz0”g?nc AHI)4")b\i4ByKAr)Z rh6 lK1R&9 %!iRK$;=""$B$Ib+1Ozw`4bpgp #LiI#LZ 6IJֳ$ yC4r)rbY#/0ByKAxj;-NoYzK/H:[,|nX)<  #b ,"zn^E 5@iy#"!z6k2 # 2 BzB9:I$iRz CP\C)#"'&#[r9YZyF; R\t< 7y-ByEy;"e'*#mBɔ|"#YA?)r"" i"[!OSSRSJ4 o4 NGS̐s4 m9:2#J<9"ID" *G""\Gyd$ or+ 64 #zr9bm9: % {E&%*N$n"~ҐH Z"Iz#Y96}4  #"@O=4 # 96@N (z949: 2 ={D[- } #LY7BIzD 2 Bz)3" r{R,G;9YҦGs`Y)r R:BYQ`,5a9 g KFyMB$&* 8yԖ D"L ’~_(xY* Ƥ}L 2 )S 4 zUSy#+Zp#]y%9KCI^C[8zi)7"9' {R%*A(H)IB&"i +Ri&!y.S Е1 1:[S ! S 00{3F *FyL"I%ZA*' %C[\r$'? j 9@? &"9#A* $iij  9p39p9 # 9RyZ 3b F,KR{&9g`9 #yi%);5$j\% ohi ħH+ħ{^ħ/ ķZ=ķh9l.d'|nj 0ʠTpiY# `|i#<  F9{i #IiDK ;9p# 'Y e9LCI_8i^#{)A/*h7@!yy!IzE<@!&INDn) # jD ZD]r"I@ %#iB $Y@|Mt%DB!@"#I'y':%{, !I#*G r"I@ "Y@L" A @YGjD^9y{,)|0͗J SI1122z4/ 4ؤ@S BS #" i#9)$;Upi<#b9 }E9I#I)#)i4b'"$y#i#YIGL H)7 >#* 6"&iZ#& PD+)1"Y", YM9& ![;% ]G d F G %[G! !LC ` B C ![C% %LG d|FyK{&i{& 4$l0ҧB9KA:lE9xB[G<$ZC:E-@:Ey"ZA:C_F,CZ@y%+D:F A Fy#BYD~OhZ{\-   Iz&ilBq> Cj! 'Ik&im&s> Cp1 y)C4{Ji6%'9ZĶ&i\ ->rI BDnR_(V'IEyZB' %y$yC{EybIAIfEIb9aLFIc:gIķzK"& &-klR"*ǰ2ږ22QS mS jS [S  #I%yKR i7Rprj" V R)4#% #RY`I{r09)#ƤFIY#zI#')#I9#: 4ai ְEI,GI|4fIJ"'*\D|$Z>! h9:lmƠ fG diC[9ّkr`ٷ}\n#i yG GI[C+ yRmD&jB9R%ICZy" $IBN I!9:Ԡ+ }NI%+7 #+4L* S1rY°$ M'"$& R?"_r (ĖI0闒h0D0m:1" Z& I # /BO8D%xZ"'ZJ' i)#$i#^* 0b EI:Rj' @#e$ JG I9z# '(7 ))#y)¢!-;" r C˰y` ZY6&![z&%j^"$ "mb 00=)`0)`Z9)6F;J" b'lr1i S44jj5@yYBI "[B |E&9. bG|#AIFy$R" .ړ2봖I9I= 2”GJfFI7봖IJ6"%iJDjB|2|6A"GyZD&!y R-A >AyoD jAl yG LR&"y" !?l2'l-?٣[S #S XS ʓ-)SЖ2 )Sז3@9S< 9SII#e#& * 6`¤Cj &Fj 4bz5‘G ZjIJ$y,DL#%>DNYB'!y*y*}IS4yIS4(1@S zS+3‘G Zjij$I,D<$I>D^C$O& B"$,\Mb :"%yƣ_YS'YSԓ5 1CSzS<6‘G ZjIJ$I,D<%;_"hiR"-!<]"#&%_YX9IY#)G=UD鐥dldf4AI C9# &\i0¡BzKA-mC<xԑk<   #`\4!ZDjD*,A =A#ID?8kė-^?b@("$h*"&!y" R"h9S 1;19 S 'YS 5O5Š_5 TS9i#9@yj6ByKA]^BZY #Z)RY%niY#Z)#k)7%$:NJS&.R>'I—k?HGzP0;6#YrZbk#<~RO“*L-R$^xY"'KAZ'J$&%I$IK=U TxR "LR T Zi)5•&KZ"+$p* rfS &6 cS 9 #)!24J#! ;990G :T kFNN0 Y #IiT B*l:y5"+ҤhYJ<]>oXI;\=ni {l^X) K<-8iJ{l]OFzI!{z“cI-ajBy %{;gYmejHFyJ!+{–c .aj By %{":-¥ "`pbp JY3B'#'j;%[#) Cː{i C 4B* 7B*Y #If%kZI6 !_” D"J2 ")_} 0P8O) 4A#Kz$ "[Y2R&9ITy%$YI>9Z# y&k079 0#YiB &"$)&` )[,Yy7%$ B$2^ror&%\ R^uCf`b`Ly0$z "j@"kO2 !$\jRIjՐ=3]*:3rI%!L%n" o“ D"J2 KRJn&&0s09,Yy7$$)zA#2OB RJI¥'$ouCa0p33mj:5$JR a#$y^!y$*”LD& 2$Rj"ғK[? pt p 95&$ ,6lr:l¥ &c`y#K9#{KI0B'#'j;&)]$ +'J}3YI#9D r997%i2YI#9D r9YI#9D R9 4Gj]7$9*TZ#Y,DL"&ynD+&)$y#j"49!*!9I#AIJm:3!%! @{AZBB[$JT)&m  @ ; C 0! jR+" "I =}+gҦ@ [A ^ҔԐ~Ҥ9ԐjҔ-Ԡ@0]d9 ]~9 ^9 pY Y @ p @< @ p#- #)]]vx }r 99ʺuv`@yy ' ' @e e > ?8 U `Us `]5 ` ^i ^! ^ , _ 03 `PV @`Ap `e ``l > ci I e @f un uP p y0ePC - 0- l @ p  `(  ǚ  xs p)   Ч-w v 0v `v @v G Pv  v  v p1 B Т`s Q Gv [ `s 0Gv f -w 0| Фv p   B     Pȝ @v ҝ v   ` p  йy)  pH 0 [ b i P      #  pp - Ԗ `^ Ԗ e  l y` 0 П  ۟ `۟   PI P p! X p P+   I ` ) i [  @i   `Au k  \ @v @O v  `s ˛ PGv  `s   P @v 0 v   l PB 0V `s ^  6 `v k v ! `s @ə Gv ``s  Gv  `s { Gv @ P8 Gv B `= `%=י @`י  p*ηޙ P,Vי י  p L px U  R@> @  =- @S7  So7 @ `U  @G  ry { Us `Ns B+ + P;2 t~ 0G PGf: u@= xs xs EG - @S S H G v v v 1 pjF jF }k ~k `w IP RSDSV&wIV+u:\develop\global\Release64\obj\AcWindows\AcWindows.pdbHH+tBHh3tBH;tBHxtBHtBHXtBH`tBHH tBH0tBH0tBH0tBH0tBH0tBH@otBHrtBH tBHPtBHڧtBH0ܧtBHtBHptBH/tBH=tBHtBHtBHtBHZtBHZtBH@`tBH@htBHtBHtBH0tBHtBHPˬtBH-tBH0ǮtBHtBHtBH tBH@tBH@ tBH tBHP"tBH`tBHtBH4xBHpi4xBH4xBH5xBH&5xBH5xBHp5xBH5xBH V6xBHЎ6xBH6xBH6xBH06xBH6xBH06xBHP6xBH6xBH6xBHP6xBHP6xBH06xBH 6xBHp6xBH6xBH`6xBH 7xBH"7xBH$7xBH`97xBH97xBHA7xBH N7xBH0Y7xBH`Z7xBHP[7xBH\7xBHP\7xBHk7xBHq7xBH@7xBH7xBHp7xBH7xBH7xBH7xBH7xBH7xBH7xBH7xBH7xBH`7xBH7xBHP7xBH 7xBH7xBH7xBH7xBHP7xBHP7xBH7xBH7xBH07xBH`7xBH7xBH7xBH7xBH`7xBH7xBH`7xBHP7xBH7xBH`7xBH|8xBH}8xBH@~8xBH8xBH8xBHp8xBH08xBH@8xBH8xBH8xBH9xBH 29xBH49xBH 69xBH@;9xBHp;9xBHD9xBHF9xBH J9xBH M9xBHP^9xBH`k9xBHn9xBH|9xBH}9xBH`9xBH9xBH9xBHp9xBHP9xBH 9xBH09xBH9xBH9xBHxBHxBHPexBH@xBHxBHxBH`xBHxBHxBH xBH@xBH`xBHxBHxBH`͊xBH07xBHpUxBHdxBH`xBHxBHpxBH@xBHxBH xBH`xBH#xBHxBHxBH0xBHǍxBHYxBHXxBHpuxBHuxBH`vxBHwxBH>xBH>xBH>xBH>xBH@@xBHCxBHPExBHFxBHxBH0xBHpxBH xBHPxBH0xBH@xBHpxBH@xBH`xBHxBHxBH`xBHxBHxBH *xBHУxBHAxBHxBHxBHpxBHxBHగxBH0חxBH`xBHxBH@|xBH`|xBH|xBH|xBH|xBH}xBH xBHpxBHxBH0xBHxBHxBH xBH@xBH`xBHxBH xBHPxBH0xBHxBH`xBHxBHТxBH࢛xBH@xBHࣛxBHpxBHxBHxBHxBHෛxBHxBHxBHxBH xBH@xBH`xBHxBHxBHxBH๛xBHxBHxBHxBH༛xBH +xBHܴxBHߴxBH hhh&hh h h!hh hh$h"h%hh#hh.H"hh?hh!hh"hh'hh!h hH'H/h h(hh9h#hh h*h h-hh,hhhhhh)h h hh/h!h4h hh"h"hhhh?'h h-hh h"h??????!h#h=h#h?$h5  L??#l??????????????=l(8@HPXء8Xxأ(0@ؤ(HPhЦئ (08@pЧ 0@P`pШ 0P`pЩ 0@P`p 0@`pЫ 0@P`pЬ @`Э 0@P`pЮ 0@P`p P 08h (X`0𤠥(0@Xئ0H`xا 8PXhȨ(@X`pЩ08HP`hxȪت (8@PhȫЫ(0@XpЬج 0H`hxح 8@PXhȮЮ(0@X`pxЯ0 08H`xؠ 8@PXhpȡС(@XpТ(0@X`pxУ0HP`xȤؤ (8@PhpȥХ(@X`pЦ0H`hxا (8@PhpȨ(@XpЩة 0H`hxȪت 8@PhpȫЫ(0@X`pЬ0HP`xح (8@PhȮЮ(@HXpxЯد@08@PXpxȠؠ (@HP`xȡСء (08@PX`pxȢآ (08HPhpxȣУ (@PXhpxФؤ @PX`pȥХإ (8@HxȦЦئ (8PX`pxȧ HpxȨШ Hp8`ت(0PXxȫЫث08X`Ьج(Pȭ@hhpP(`ȢТhȤФؤPX`hȥ08@Hpx𧨨 ةੈxȫhx8@xȭHPX(8ȯ` @РؠȡС`hТ8أxȤФؤȥ`PبHة@pتȫЫث PXxЬج0PȮȯЯدpX @Hhpxؠ(08@HX`pء(08XТآ 08@HPX`hpxȢТآ (08@HPX`hpxȣУ(0HPhpȤФ(0HPhpȥХ (08@HPX`hpxȨت (08@HPX`hpxȫЫث (08@HPX`hpxȬЬج (08@HPX`hpxȭЭح (08@HPX`hpxȮЮخ (08@HPX`hpxpPФؤ h@Ȧ8Hx8PȪhxЫ(8Hx8Pȭ`pH`Я Hx(8H0@pآ0X`p 0@(8Ц(h`xXpxЪ8@P` PЬxЭ8@P` PЯ(x8P` PТx8P`ȥ`xЦ 0`xȧا pȨ(XpЩhx hȫ`pH`Xh@XP`8PHX0Hأ@P(@Х8H 8ȧ0@pب0ة(8hЪ(xЫ 0`xȬج pȭ(XpЮhx  PhȠ`p`ȢXأPФؤ0Hإ@P(@Ч8Hx 8ȩ0@ت0ث(8hЬ(xЭ 0`xȮخ pȯ0(XpРhx PhȢ`pH`Xh@XP`8P@HX0H@P@Ь8H0@(8hЯ@(xР8PXpȡ(pآ hУ`ȤXإ8P`xXpxШ8H80@ث0ج(8hЭ(xЮ 0xȯدP pȠ(pСhx Phȣ`p`Xh@XP`PHXH@P@8H8`0@ؠ0ء(8Т(xУ 0xȤؤ pȥ(pЦhx hȨ`p`XhXP`PHXpH@P@Т8H 80@إ0ئ (8Ч(xШ 0`xȩة pȪ(XpЫhx Phȭ`pH`PxX`ءH`Ȣآ УȤXХ HXpЦЭHhȮЮ Hp 8`Р @hء(0PXxآ(0PXxУ @Hhp08X`xȥ8`Ц @`xȧ@hШب@HxةXhx0Hȫ8XpȬ0H`pȭ(HhȮ 8Hد 0HXxdp 8 0Xhȭح8Hp8@HP`ȯЯدx (8X`hpȠ08@HXxȡСء 0PX`hxأ(@( PxX0@hx(X`hpȤ08@HXxȥХإpЫج8X`hPȣ8(8ئP`pЧ(8Hh8Hpȭح 0P  @PȨШب0PD(Hx` (0@ pث(ؠ x P`@pЮЯ (P`H(8Pxȧا ثP`p `p0@Pp @XЯ0l(x0HpС࢈PȦ0ЧhȪ HحPxP@H(Ȣ@@8hPhhhX`PHh p@H(p` X`h ``H(Ȣx `p0@Pp`ȫ0p(PXxȤ08X`Хإ (HPh08PX`hpxȧЧا hȤФ(Hhȥ(HhȦ(HXhȧ(HXhpȨ(Hhȩ(HhȪ(Hhxȫ(HXhȬ(Hhȭ(HPhxȮ(8Hhȯ ,(HhpȠ(0Hhȡ(HhȢ(HPhȣ(HhȤ(Hhȥ(HhȦ(Hhȧ(HhȨ(Hhxȩ(HPhȪ(8HPXhxȫ(HhȬ(0HXhȭ(h8pȯ0xРHȡ8(ppXhȥP(ȧЧا0xȨШب (h 8P`Ȫت(8hxpXh0p@`@@ؠ PȡС8hآУأ(Xx (@HP0XȦ(8Hȧ(08h @XЩ@`Ъ@PpЫث8`hHЭ(0X8hȮ0¦Ҧ"2BRbr§ҧ"2Bhr¨ب"2BRbr©ҩ0HXxȪP @JZjج(2BRhr­ҭ"Pxʮڮ"2Hp@x@xФ(h x§ҧ"2BXHX(P *:pzȬxPЮPl8p Ҡ"2BRb`jzxhr HRȫx8 x`(hРڠ0:JZ(@JZjȢ *:Xpzʣ *(@h0H(P(HhШ @0PpЪ(Hhث HhȬ8`0Ȯ(Xدp<Сʢڢ (`У0PxHPX`hpxȠРؠ (08@HPX`hpxȡСءdPX`hأ (08@HPX`hpxȤФ (08@HPX`hpxȥ (08@HPX`hpxȦЦئ (0HPX`hpxȧЧا(HPX`xȨШب (08HXЩة (08@HP`pxȪت (8@P`pxȫث (08HPX`hpج (08@HPX`hpxЭح 8@HPXhȮЮخ (08@HPX`hpxȯЯد 0@P`hȠؠ (8HPhpxС 08@HPX`hpxȢТآ (08@HP`pУ 0@H`hpxؤ (08@HPX`hpx (08@HPX`hpxЦئ 8@HPXhpȧЧ@HPXpxȨШب (08PX`hpxȩЩة 0PX`hȪЪت (08@P`pxȫЫث(0HPX`hxȬ (08@HPX`hpxЭح (8HX`hȮЮخ (08@PX`hpxȯЯد (08@HPX`hpxȠРؠ 0@P`pȡء(8HX`xȢТHPX`hxУ (08@PX`hpxؤ (0@P`ȥХإ (08@HPX`hpȦ (08@HPX`hpxЧا (08HPX`hpxȨب (08HP`pxȩЩ (8HXhpȪЪت PX`hpȫЫث (08@HPX`hpxȬج8@HPXhpxȭЭح (08@HPX`xЮ 0@H`hpxȯد(08@HX`hpxȠРؠ (08@HPXhp (08@HPX`hpxȢТ(08@X`hpxȣУأ (8HXhpФ (0@PXȥХإ (08@P`pxȦЦئ(8HPXȧЧ (08@PX`hxȨШ (0@HX`xة (08@P`pȪЪ (08@HPX`hpxȫЫث(8HX`hȬЬج X`hpȭЭح (PXhxȮЮخ (08@PX`hpxȯ(08@HPX`hpxȠРؠ 8@P`pȡСء (08@HPX`hpxȢآ(08@HX`pxȣУأ(8HPhpx (08HXȥХإ (08@HPX`hpxȦЦ 0`hpxȧЧا (08@HPX`hpxȨب 8@HPXhpxЩة (08@HPXhxȪЪت (08HXhxȫЫث08@HP`hxȬЬج (@HPX`pxȭح(0@PhpxȮЮخ (08@HPXhxȯЯد (08@HPX`hpРؠ (08@HPX`hpxȡСء 0@P`pآ (08@HXhxȣУأ (08@HPX`hxؤ (@HPX`px (08@HPXhxȦЦئ PX`hpȧЧا (08@HPX`hpxШ 08hpxȩЩة PX`hpȪЪت (08@HPX`hpxЫ 0`hpxȬЬج (08@HPX`hpxЭ 0@H`hpxخ (08@P`pxȯЯد(0HPX`hxР (0@HPX`hpxС08@HP`pxȢآ 0@P`pУأ (08@HPX`hpxȤ(8HPXȥХ (08@PX`hpxȦЦئ (08@H`hxȧЧ 0@PXpx (08@HPX`hxة (08@HPX`hpxȪت(8hpxȫЫث(8HXhpȬЬج (08@PX`hpxЭ(08@HX`hpxȮخ (8@P`hȯد (8HPXȠР 08HXpxȡСء 08@pxȢТ 0@H`hpxȣأ(08@HX`hpxȤФؤ(0`hpxȥХإ 8@HPXhpxЦئ (8HX`xȧЧ PX`hp (08@HPX`hpxȩЩة(0@P`pȪЪت (@HPX`pxЫ08@HP`hpxȬج (@HPX`hpxȭЭح 0`hpxȮЮخ (08@HPX`hpxȯد8@HPXhpxȠРؠ (08@HPX`hpxȡء 8@HPXhpȢТ(08@HX`hpxȣ (08@HXhxФؤ (@P`hpХإ (08HP`pȦЦئ (08@HPX`hxЧا (08@P`pШب (08@HPX`hpxЩة (8HX`xЪ 08@HPX`hpxȫЫث (08@PXhx (08@HPX`hpxȭح (8@P`hȮخ (08HPX`hpxȯЯد  (08@X`pȠ (08@HXhxȡСء (08@HPX`hpxȢТآ 0@P`pУأ (08@HPX`hpxȤ(8HxȥХإ (08@HPX`hpxȦئ(8HX`hpȧЧ (08@P`pȨШب (08@HPX`hpxȩЩة(8HXhpxȪЪت (08@HP`pث (08@HP`pȬЬ(8HPXpxȭЭح 0HPX`hxȮЮ(08@HX`pЯد0 (8HPXpxȠРؠ (@HPX`pxȡСء 0@P`hȢآ (8@P`hȣУأ 8@HPXhpȤФؤ (0@P`pxȥإ (08HPX`hpx (08@HPX`hxȧЧا 0`hpxȨب (8@HPX`hpxȩЩة (08@HPXhxȪت (08HPX`hpȫЫ(8HȬЬج(8HXhpЭ (8@HPX`hpxȮ(08@P`xȯЯد@(8@X`hpxР (0@HPX`hxСء (08PX`hpxȢТآ 0@pxȣأ (8@HPX`p (08@HPX`hpxХ (0@HXhpЦئ(8HX`xȧ(08@PXpxȨب8@HPXhpxȩЩة (08@HPX`hxЪ 08HXhȫЫث (08@HPX`hpxȬج 0@H`hpxȭ(08@HPX`hpxȮخ (08@PX`hpxЯP (8@HPX`hpxȠРؠ (08@HPX`pȡСء (08HXhxȢТآ 08PX`hpȣУ(@HPX`pxȤ (08@PX`hpxȥ(08@HPX`hpxЦ(08@HPX`hpxȧ(08@PȨШب (08@HPX`hpxȩЩ 0@P`hȪت(08@HX`hpȫЫث (08HXhxȬج (08@HPX`hpxȭЭح 0@P`ȮЮخ (08@HPX`hpxȯЯ`(8pxȠРؠ (08@hp (08@HPX`hpxȢТآ (8HXhxȣУأ 0@pxȤФؤ (08@HPX`hpxȥإ 8@HPXhpxЦئ (08PX`hȧЧا (08@HPX`hpxȨШب 0@P`pxȩЩ (08@HPX`hpxȪЪت 0@P`pȫثHPX`hxȬЬج (08@HPX`hpxȭح(@HPX`pxЮخ (08@HXhxȯЯدp(8hpxȠР 08@HPXhxȡСء (08@HPXhxȢТآ08@HP`hpxȣУ (08@HP`pȤФؤ0@PXȥХإ (08@HPX`hpxЦئ(8hpxȧЧا (X`hpxȨШHPX`hxȩЩة (08@HPX`hpxȪت(@HPX`pxȫث(0@PXpxȬЬج(08@HX`pȭЭ(08@HX`pЮخ08@HP`hpxȯد (8HPhpxȠРHPX`hxȡСء (@HPX`pxȢТآ 0@PXpxȣأ(08@HX`pȤФؤ (0@P`pxȥХ8@HPXhpxȦЦئ (08@HPX`hpxЧا(8HX`xȨШب08@HP`hxȩة 0@HxЪت (0@HPXhpxث (08@HPX`hpxȬج(08@`hpxȭЭ08@HX`hpxȮЮخ (08@HPX`hpxȢآ (0@HPX`hpxȣУ (08PX`hФؤ (PX`hx (08hpxЦئ (0@HPX`hpxpx (08@hpxة PX`hЪتX`hpЫثPX`hج (08@HPX`hpxح 8@HPȮЮ (0Яد08@H`hpxȠРؠ (08HPX`hpxȡСء (08@HPX`pТ8@HP`hpxȣУأ X`hp08@HPX`hpxȥХإ xȦЦئ (08@HPX`pȧX`hpȨШب (08@HPX`p(08@HPX`hpxȪЪت 0@PȫЫث 08ȬȭЭح (08@HPX`hpxȮЮخ (08@HPX`hpxȯЯد (08@HPX`hpxȠРؠ (08@HPX`hpxȡСء (08@HPX`hpxȢТآ (08@HPX`hpxȣУأ (08@HPX`hpxȤФؤ (08@HPX`hpxȥХإ (08@HPX`hpxȦЦئ (08@HPX`hpxȧЧا (0@HXhxȨȩЩة (08@HPX`hpxȪЪت (08@HPX`hpxȫЫث (08@HPX`hpxȬЬج (08@HPX`hpxȭЭح (08@HPX`hpxȮЮخ (08@HPX`hpxȯЯد (08@HPX`hpxȠРؠ (08@HPX`hpxȡСء (08@HPX`hpxȢТآ (08@HPX`hpxȣУأ (08@PXhxȤؤ (@HPXХإ (08@HP`Ȧ (08@HPX`pȧЧ (08@HPX`hxȨШب (08@HPX`hpxȩЩة (08@HXhxȪت 8@HPȫЫث`hpxȬЬج(08@X`hpx(08@HPX`hpxȯЯد (08@HPX`hpxȠРؠ (08@HPX`hpxȡСء (08@HPX`hpxȢТآ (08@HPX`hpxȣУأ (08@HPX`hpxȤФؤ (08@HPX`hpxȥХإ (08@HPX`hpxȦЦئ (08@HPX`hpxȧЧا (08@HPX`hpxȨШب (08@HPX`hpxȩة (08@HPX`hpxȫЫث (08@HPX`hpxȬЬج (08@HPX`hpxȭЭح (08@HPX`hpxȮЮخ (08@HPX`hpxȯЯد (08@HPX`hpxȠРؠ (08@HPX`hpxȡСء (08@HPX`hpxȢТآ (08@HPX`hpxȣУأ (08@HPX`hpxȤФؤ(8HXhxإ (08PX`hpx8@HPhpxȧЧا (08@HPX`hpxȨШب (08@HPX`hpxȩЩة (08@HPX`hpxȪЪت (08@HPX`hpxȫЫث (08@HPX`hpxȬЬج (08@HPX`hpxȭЭح (08@HPX`hpxȮЮخ (08@HPX`hpxȯЯدd (08@HPX`hpxȠРؠ (08@HPX`hpxȡСء(0@P`pX`hpȣУأ (08@HPX`hpxȤФؤ (08@HPX`hpxȥХإ (08@HPX`hpxȦЦئ (08@HPX`hpxȧЧا (08@HPX`hpxȨШب (08@HPX`hpxȩЩة (08@HPX`hpxȪЪت (08@HPX`hpxȫЫث (08@HPX`hpxȬЬج (08@HPX`hxȭح (@HPX`hpЮخȯЯد (08@HPX`hpxȠРؠ (08@HPX`hpxȡСء (08@HPX`hpxȢТآ (08@HPX`hpxȣУأ (08@HPX`hpxȤФؤ (08@HPX`hpxȥХإ (08@HPX`hpxȦЦئ (08@HPX`hpxȧЧا (08@HPX`hpxȨШب (08@HPX`hpxȩЩ 0@xȪЪتȫЫث (08@HPX`hpxȬЬج (08@HPX`hpxȭЭح (08@HPX`hpxȮЮخ (08@HPX`hpxȯЯد (08@HPX`hpxȠРؠ (08@HPX`hpxȡСء (08@HPX`hpxȢТآ (08@HPX`hpxȣУأ (08@HPX`hpxȤФؤ (08@HPX`hpxХ  (08@HPX`hpxȧЧا (08@HPX`hpxȨШب (08@HPX`hpxȩЩة (08@HPX`hpxȪЪت (08@HPX`hpxȫЫث (08@HPX`hpxȬЬج (08@HPX`hpxȭЭح (08@HPX`hpxȮЮخ (08@HPX`hpxȯЯد   (08@HPX`hpxȠР 0PX`h08@HPX`hpxȢТآ (08@HPX`hpxȣأ(08@pxФؤȥХإ (08@HPX`hpxȦЦئ (0@Ppxا HPX`xȨШب08@H`hpxةȪЪت (08@HPX`hpxȫЫث (08@HPX`hpxȬЬج (08@HPX`hpxȭЭح (08@HPX`hpxȮЮخ (08@HPX`hpxȯЯد0 (08@HPX`hpxȠРؠ (08@HPX`hpxȡСء (08@HPX`hpxȢТآ (08@HPX`hpxȣУأ (08@HPX`hpxȤФؤ (08@HPX`hpxȥХإ 0@P`pЦئȧЧ (08@HPX`hpxȨШب (08@HPX`hpxȩЩة (08@HPX`hpxȪЪت (08@HPX`hpxȫЫث (08@HPX`hpxȬЬج (08@HPX`hpxȭЭح (08@HPX`hpxȮЮخ (08@HPX`hpxȯЯد@t (08@HPX`hpxȠРؠ (08@HPX`hpxȡСء (08@HPX`hȢآ@HPX`pxȣУأ (08@HPX`hpxФ 0@Pإ (08@HPȦЦئȧЧا (08@HPX`hpxȨШب (08@HPX`hpxȩЩة (08@HPX`hpxȪЪت (08@HPX`hpxȫЫث (08@HPX`hpxȬЬج (08@HPX`hpxȭЭح (08@HPX`hpxȮЮخ (08@HPX`hpxȯЯدP (08@HPX`hpxȠРؠ (08@HPX`hpxȡСء (08@HPX`hpxТHPX`xȣУأPX`hȤФؤȥХإ (08@HPX`hpxȦЦئ (08@HPX`hpxȧЧا (08@HPX`hpxȨШب (08@HPX`hpxȩЩة (08@HPX`hpxȪЪت (08@HPX`hpxȫЫث (08@HPX`hpxȬЬج (08@HPX`hpxȭЭح (08@HPX`hpxȮЮخ (08@HPX`xЯ` 8@HPȠРؠ (08@PpxȡС (0HPX`hpxȢآ (08PX`hpxȣУ(08@X`hpxȤФؤ08@H`hpxȥХإ (@HPXئ (08@HPXhȧ (08@HPX`pШب 08xȩЩة@HPXpxȪЪ 8@HPX`hpxЫث (08@HX`ȬЬج (`hpxȭЭح(08@X`hpخ(08@X`hpȯЯp08@HX`hpxȠРؠ (08@PXhx(08@HPX`hpxȢТآ 0ȣУأ (08@HPX`px (08@HPXȥХ (08@HPX`hpxȦئ (08PX`hpxȧЧا 0@ȨШب (08@HPX`hpxȩ08@HhpxЪتpxȫЫث (@HȬЬج (08@Эح (08@HPX`hpxȮЮخ 08X`hpȯ (08@HX`Рؠ X`hpȡС 8@HPX`hxȢТآ(0X`hpȣ (0HPX`px (08@PXȥХإ (0@HPX`hpȦئ HPX`pxا (0@HxȨШ (8@HPX`hxȩЩ(0PX`hx (08@HX`ȫЫث (08HPX`hpxȬЬ (HPX`px(08@خ (08@HPX`hpxЯد (8@ȠРؠ (08@HPX`hp (08HPxȢТ (8@HPX`hxУأ8@HP`hpxФؤ (8@Хإ (08@HPX`hpxȦЦئ(0`hpxȧЧ (08@HP`hȨШب@HPXhpxة (0@HȪЪت (08@HPXpxЫث@HPXhpx (8@HPX`hpxȭ08@H`hpxȮЮخ(8X`hppxȠРؠ (08@HPX`hpxȡСء (08@HPX`hpxȢТآ (08@HPX`hpxȣУأ (08@HPX`hpxȤФؤ (08@HPX`hpxȥХإ (08@HPX`hpxȦЦئ (08@HPX`hpxȧЧا (08@HPX`hpxȨШب (08@HPX`hpxȩЩة (08@HPX`hpxȪЪت (08@HPX`pxȫثЬج (08@HPX`hpxȭЭح (08@HPX`hpxȮЮخ (08@HPX`hpxȯЯد (08@HPX`hpxȠРؠ (08@HPX`hpxȡСء (08@HPX`hpxȢТآ (08@HPX`hpxȣУأ (08@HPX`hpxȤФؤ (08@HPX`hpxȥХإ (08PXhxȦЦئX`hpȧЧا(0 (08@HPX`hpxȩЩة (08@HPX`hpxȪЪت (08@HPX`hpxȫЫث (08@HPX`hpxȬЬج (08@HPX`hpxȭЭح (08@HPX`hpxȮЮخ (08@HPX`hpxȯЯد (08@HPX`hpxȠРؠ (08@HPX`hpxȡСء (08@HPX`hpxТ𢘣ȣУأ (08@HPX`hpxȤФؤ (08@HPX`hpxȥХإ (08@HPX`hpxȦЦئ (08@HPX`hpxȧЧا (08@HPX`hpxȨШب (08@HPX`hpxȩЩة (08@HPX`hpxȪЪت (08@HPX`hpxȫЫث (08@HPX`hpxȬЬج (0HP`p(08@HPX`hpxȮЮخ (08@HPX`hpxȯدP`hpxȠРؠ(08@X`hpСء08@HPX`hpx (ȣУأ (08@HPX`hpxȤФؤ (08@HPX`hpxȥХإ (08@HPX`hpxȦЦئ (08@HPX`hpxȧЧا (08@HPX`hpxȨШب (08@HPX`hpxȩЩة (08@HPX`hpxȪЪت (08@HPX`hpxȫЫث (08@HPX`hpxȬЬج (08@HPX`xЭ (08PX`hخ (08@HPX`hpx (08@HPX`hpxȠРؠ (0PX`hpPX`hpx 0@H`hpx (PXpx 08@Hpx (08@HPX`hpxȦЦئxШ`hpxȩЩة (08@HPX`hpxȪЪ 08pxЫȪتHhpxȫHXpxЭ@`hpЮPX`hpx Xxؠ (`pС 0@P`pТ 0@P`pУ 0@P`pФ 0@P`pХ 0@P`pЦ 0@P`pЧ 0@P`pШ 0@P`pЩ 0@P`pЪ 0@P`pЫ 0@P`pЬ 0@P`pЭ 0@P`pЮ 0@P`pЯ0 0@P`pР 0@P`pС 0@P`pТ 0@P`pУ 0@P`pФ 0@P`pХ 0@P`pЦ 0@P`pЧ 0@P`pШ 0@P`pЩ 0@P`pЪ 0@P`pЫyara-4.5.3/tests/data/ChipTune.efi000066400000000000000000001100041501365277300167430ustar00rootroot00000000000000MZPEd 8A p .textPP `.data``@.reloc pp`b.debug`bUHHpHyQ11E1E11!)1(11E1E1B0HMHU=HxzH}vsHEHHLE1HxlHEHHLE1Hx`HEHH LE1HxTH}rYHEHH(LE1HyIH 6H 5v&H 6H H6H 6xHE1HEHEHEHHH6$HtHEHHH6#HtHM)H:PH NLE1@HxHMH9t HH 6H%HEHEHHHY6#HtHEHHH6g#HuAHOH FNLE1@Hx HMHyuH _6HM%HEULELMHEHD$ H r6%%HEHtMHULE HMHtULELMHEHD$ QHy HH [6H$1Hp]UHVWSH(HH8#HHyGtCt"tHO6IH \6L_6`HH #H?HyGtCt"tH5IwH 5L6HH%$HHyGtC1t"5tH5IH 5L5HH%HHyGtCt"tH25I H ?5LB5C$H(HyOtKyt"}tH5I` H 4L!5H([_^] H([_^]UH]UH]zUHVWSH8HHHLH LHKLEHxHEHHHHHLH LHeKLEHx$HEH@8HtEHKHKHt(91tH9ruf|~Hu1HH([_^]/(j(E(UHH |HHH ]UHf ]UHQAfC]Ðffjff`ft$s t f1fgl$8fnf^fffffg.ff".fWf20f"fHþҎڎŽf"20"fff]g$:FP.f^faffgd$fːUSVWSSSHDF6~ gHAkjYJtЃ fB D$`LT$`LIfDQLYHt$bIHILLL$P A% iDjZQ:ҜRLAPAfDA%Ha*i4T$`\$PE[[[_^[]SȉPLT$8MtA LLHL$@X[SPRMtA YLHL$8X[Ë6t& sRHHH)HHHZHHaHiHyHq La(Li0Lq8Ly@QPoqXoyhDoAxDoDoDoDoDoDoDoHaHQHH YZH1H5t sHHHHHaHiHyHq La(Li0Lq8Ly@HQHYPqXyhDAxDDDDDDDH1HHLIa  HH" HH" ÉUHAMt H1IAH1I]UHVH(HPHuu H(^]#UHVH(H&Huu H(^]#UHVH(HHuu HH(^]#UH]H52|$(HNH)H$H)AQHYDDDЃQARHˉ "ӹ20 $"WVrH1frH1ÉHrH1HH H UHAWAVVWSH(IH ILHþHHHLHL1H1H H([_^A^A_]WHLHHHGHE_WHLHHGHE_WHLHfHGHE_WHHLHGHE_VWHHLHFHWH)_^WQH1HHHHHX_WHLHHH_WHLHH_WHLHfH_WLHHH_VWHHNLH9HsI9sLIHH LJ|L_^WHHHHH1HuHu__H1UHVWH@HHLE LM(Hu 1$udHM HMHtLMHHIP5~t,HLMкHIHZ?HH@HQH@_^]!UH{1$]UHH0IH=LD$(HT$ H)I.@1H0u u]]]`UH 1 ]UH 1]UHH H>Hu>H>H u=L=1@HxH=8 t H=1H ]UHH0HH]>LEP@HxHE HE1H0]UHVH(H&>PHHHyMtI%t")tH%I H (L%-H(^]H(^]ÐUHAWAVAUATVWSHMHHILEt/D% Hu">HuHLLE@D% H t"MuMLLEA@u'5]/AHtILL9s/t+h5:/AHt"LL9sH9LEHpArC=.AHtziwtLHH9@LHA=.AHt7&wtLHH9LHH9LLEwA r"HHpu$1H[_^A\A]A^A_]HHpHDHIHHHDA1ɃtAN D!HEHUHp HM8HME1L|L.H9r H A@!f Lhf f%bHEE11HEI41AHtN D!HEf)Hf"H Hc HHHE1H w;1K4A ^Ht AT^L$pI D!HMHQIHH rLH A LCHEICHEHEIBHE>f II(flIIIIIIIIIIA r,IHEHt2HHM#Dу I HEHt$HHMH.HU0HHHH HHEHU0HHHH HHE1HEI\I1A HtP D! LDL&H&LDHMHE1HELAI1A HtP D! LDHMHE1HELLI&E11HEE11HEE1LIHE1HELLUE11HELE11HME1fu L1HMfW~6HfHUH HcHHWHB^f HUt,f t_fSIHHHJH1 HtP D!HM HD1HEL>%H1 HtP D!HM HDL%H%LDHU0HHHH 1HMLLHMLDHV$LDLH4H?H!MfXt7I1HELUHHuhHHJlIII IȀExII@Au HtBHcHtKHHHUUHLZHHHHUHU0HHHH HcHU0HHHH H1HML0B Aѹ+EHUEHuxSDHMLHAIDHUHEHUrBHy=HHuHؾ -HMH?HHIAHEȾ1HELEHu@@HEȾ ƅ0H`HMHM#L||B 1AL$IHuH0I)H`H EIEHHHHHRHH)IӸI1HLDÌ}t"IHtHAHHIIIL)I01ɀ}HUHIHMHH ! HDUHUAHuHu1 HCHuAI)I rIIJE1HEqHuA d9fA sI9s օutILIHEL9IBDH`HuVHMH)HIHhHtH^HuuSHHIM[HMtHtLHAW1HHHH-HH([_^A^A_]oJUHH@HEHL@LHLEIH*HP@H@]UH1]UHAWAVATVWSH IIMuuqMuuhIH)1IH9Cht511HSpHL&uHHH;{hrHCpHD0IE1LH [_^A\A^A_]  UHVH(HY)Hu~H 'HF)7HHyGtC;t"?tHI"H L0H(tHtH(^] UHH S1H ]UH1] "UHVH8H (H8H~'LEMHx&HMHUE1E1Hx9ut HMQuH8^]UHVWSHHt7H +(HHm'HHLAAQ XLEIH'H 'HI8H&HHxUt*@tHEH@DHa@HHEHH9taH&Ht"@tH@InHB'H &LE1@H<Ho1t@5tH@H&HMHL$ H%LMȹE18Hx1HEH HtuHUH &Hy81H H9u@HH9rQH@H@IHZ&H3%LEHYt"@]tH@I@HMHx^H&H %HI8LEH$H%H %H8LEH$E1HHHxDHEH %+t"tHwIHHH[_^]ttH IrUHAVVWSH LHIx$HL9u\H #HtH^$Ht:H16H #Hqt H$H #11I@HyLHH [_^A^]UHAWAVAUATVWSHhDMEHDEĉUA tK@t=1EHKIT$8L$0D$(ED$ HU@DEDM`Nt]@RtOHCHxL@DH HtG WO 111|$8L$0T$(D$ H)@HCD MHE1LmH}HىMIIMt8@t*HEDHH@ D$(L$ @HA~HMAEtn;EE9Au{E wsHHsaA tluNtJ@&t<@HuAM#;EvQ uQ;Uv UĉEHuHI9/A==t=u=t=uK HEHHxQHCxH9HH@hH'@AH++1EML$ D$(HDEDMqt-@tEĉD$ H@ADMHىSHHx?t'@tHCD@H@HHh[_^A\A]A^A_]ÄtbtHCDHEĉD$(ED$ HfA8UHAVVWSH0EƉ׉EH H LE1@Hx8HM؉AHyVHtJtZc UHH H L j=ZC UHH H L j\Z# UHH H L j[Z UHH H L j1Z Usage: ChipTune <any|hda|beep> <count> <signal> <silence> [<frequency>] Invalid count value - %r Invalid signal length value - %r Invalid silence length value - %r Invalid frequency value - %r anybeepBeep protocol is unusable - %r hdaHDA protocol is unusable - %r Trying playback %u %Lu %Lu %d Playback failure - %r SelfChipTune ASSERT_EFI_ERROR (Status = %r) AutoGen.c!EFI_ERROR (Status) ASSERT_RETURN_ERROR (Status = %r) !RETURN_ERROR (Status)Buffer != ((void *) 0)OCM: LoadedImage cannot be located - %r SetJump.cJumpBuffer != ((void *) 0)((UINTN)JumpBuffer & (8 - 1)) == 0Divisor != 0DivU64x32Remainder.cSafeString.c%a(%d) %a: SAFE_STRING_CONSTRAINT_CHECK(%a) failed. Return %r /Users/runner/work/OpenCorePkg/OpenCorePkg/UDK/MdePkg/Library/BaseLib/SafeString.cStrDecimalToUintnS(String != NULL)(Data != NULL)(StrnLenS (String, RSIZE_MAX + 1) <= RSIZE_MAX)String.cString != ((void *) 0)((UINTN) String & 0x00000001) == 0Length < _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLengthStrSize (FirstString) != 0StrSize (SecondString) != 0Unaligned.cOcDebugLogLib.cFormat != ((void *) 0)ASSERT [%a] %a(%d): %a MemoryAllocationLib.cPrintLibInternal.c(Buffer != ((void *) 0))(BufferSize <= (_gPcd_FixedAtBuild_PcdMaximumAsciiStringLength))(Format != ((void *) 0))(BufferSize <= (_gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength))(StrnLenS ((CHAR16 *)Format, (_gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength) + 1) <= (_gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength))(AsciiStrnLenS (Format, (_gPcd_FixedAtBuild_PcdMaximumAsciiStringLength) + 1) <= (_gPcd_FixedAtBuild_PcdMaximumAsciiStringLength))%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x%02d/%02d/%04d %02d:%02d%08X PrintLib.c(((UINTN) (StartOfBuffer)) & 0x01) == 0(((UINTN) (FormatString)) & 0x01) == 0OcUnicodeLib.cUefiRuntimeServicesTableLib.cgRT != ((void *) 0)UefiBootServicesTableLib.cgImageHandle != ((void *) 0)gST != ((void *) 0)gBS != ((void *) 0)UefiLibPrint.c((UINTN) Format & 0x00000001) == 0Console != ((void *) 0)UefiLib.cTableGuid != ((void *) 0)Table != ((void *) 0)HobLib.cmHobList != ((void *) 0)OCC: GOP exists on ConsoleOutHandle and has %u modes OCC: Looking for GOP replacement due to invalid mode count OCC: No handles with GOP protocol - %r OCC: Alternative GOP status is - %r OCC: Installing GOP (%r) on ConsoleOutHandle... OCC: Failed to install GOP on ConsoleOutHandle - %r OCC: Missing compatible GOP - %r OCC: Requesting %ux%u@%u (max: %d) resolution, curr %u, total %u OCC: Current FB at 0x%LX (0x%X), format %d, res %ux%u scan %u OCC: Mode %u failure - %r OCC: Mode %u - %ux%u:%u OCC: No compatible mode for %ux%u@%u (max: %u) resolution OCC: Current mode matches desired mode %u OCC: Setting mode %u with %ux%u resolution OCC: Failed to set mode %u (prev %u) with %ux%u resolution OCC: Changed resolution mode to %u OCC: Failed to force resolution - %r OCC: Missing OcForceResolution protocol - %r OCC: Missing GOP on ConOut - %r B@B/B@0123456789ABCDEFSuccessWarning Unknown GlyphWarning Delete FailureWarning Write FailureWarning Buffer Too SmallWarning Stale DataLoad ErrorInvalid ParameterUnsupportedBad Buffer SizeBuffer Too SmallNot ReadyDevice ErrorWrite ProtectedOut of ResourcesVolume CorruptVolume FullNo MediaMedia changedNot FoundAccess DeniedNo ResponseNo mappingTime outNot startedAlready startedAbortedICMP ErrorTFTP ErrorProtocol ErrorIncompatible VersionSecurity ViolationCRC ErrorEnd of MediaReserved (29)Reserved (30)End of FileInvalid LanguageCompromised DataIL9wד:'?Mi$24FyhR_2#VOX R$61/uNO*hʡ1?ir;rB:$ީB#8JzЀQj),A8wh9w/.LVIC!~#M%wO6 H0"` MTOC9蕙Y9w~k/Users/runner/work/OpenCorePkg/OpenCorePkg/UDK/Build/OpenCorePkg/DEBUG_XCODE5/X64/OpenCorePkg/Application/ChipTune/ChipTune/DEBUG/ChipTune.dllyara-4.5.3/tests/data/bad_dotnet_pe000066400000000000000000000100001501365277300172440ustar00rootroot00000000000000MZ@ !L!This program cannot be run in DOS mode. $PELS" 0~& @ `,&O@0` T%T  H.text  `.rsrc0@ @@.reloc`@B`&Ha.rp( *( *BSJB v4.0.30319l#~#Strings4#US#GUID,#BlobG 3  yAIt_(] (1P #\   )19AIQYi?a. '.0.O.#X.+.3.;.C.K.S0!Class1funcHelloWorldSystem.ConsoleSystem.RuntimeWriteLineDebuggableAttributeAssemblyTitleAttributeTargetFrameworkAttributeAssemblyFileVersionAttributeAssemblyInformationalVersionAttributeAssemblyConfigurationAttributeCompilationRelaxationsAttributeAssemblyProductAttributeAssemblyCompanyAttributeRuntimeCompatibilityAttributeSystem.Runtime.VersioningHelloWorld.dllSystemSystem.Reflection.ctorSystem.DiagnosticsSystem.Runtime.CompilerServicesDebuggingModesObject1im.litianxiong@gamil.comM7 t    ?_ :TWrapNonExceptionThrows5.NETCoreApp,Version=v6.0TFrameworkDisplayName HelloWorld Release 1.0.0.0 1.0.0"MP]%'&RSDS0A ¯FU)>C:\ws\dotnet\HelloWorld\HelloWorld\obj\Release\net6.0\HelloWorld.pdbSHA2560A ¯VU)>"[SzK,T&n& `&_CorDllMainmscoree.dll% 0HX@4VS_VERSION_INFO?DVarFileInfo$Translation4StringFileInfo000004b06 CompanyNameHelloWorld> FileDescriptionHelloWorld0FileVersion1.0.0.0>InternalNameHelloWorld.dll(LegalCopyright FOriginalFilenameHelloWorld.dll6 ProductNameHelloWorld0ProductVersion1.0.08Assembly Version1.0.0.0 6BSJByara-4.5.3/tests/data/base64000066400000000000000000000034241501365277300155550ustar00rootroot00000000000000Plaintext Encoded Substring This program cannot VGhpcyBwcm9ncmFtIGNhbm5vdA== VGhpcyBwcm9ncmFtIGNhbm5vd AThis program cannot QVRoaXMgcHJvZ3JhbSBjYW5ub3Q= RoaXMgcHJvZ3JhbSBjYW5ub3 AAThis program cannot QUFUaGlzIHByb2dyYW0gY2Fubm90 UaGlzIHByb2dyYW0gY2Fubm90 These are the wide versions of the string. To make it easier I'm splitting them each onto their own line. This program cannot VABoAGkAcwAgAHAAcgBvAGcAcgBhAG0AIABjAGEAbgBuAG8AdAA= VABoAGkAcwAgAHAAcgBvAGcAcgBhAG0AIABjAGEAbgBuAG8AdA AThis program cannot QVQAaABpAHMAIABwAHIAbwBnAHIAYQBtACAAYwBhAG4AbgBvAHQA QAaABpAHMAIABwAHIAbwBnAHIAYQBtACAAYwBhAG4AbgBvAHQA AAThis program cannot QUFUAGgAaQBzACAAcAByAG8AZwByAGEAbQAgAGMAYQBuAG4AbwB0AA== UAGgAaQBzACAAcAByAG8AZwByAGEAbQAgAGMAYQBuAG4AbwB0A These are the ascii strings converted to base64wide VGhpcyBwcm9ncmFtIGNhbm5vdA== QVRoaXMgcHJvZ3JhbSBjYW5ub3Q= QUFUaGlzIHByb2dyYW0gY2Fubm90 These are the wide strings converted to base64wide VABoAGkAcwAgAHAAcgBvAGcAcgBhAG0AIABjAGEAbgBuAG8AdAA= QVQAaABpAHMAIABwAHIAbwBnAHIAYQBtACAAYwBhAG4AbgBvAHQA QUFUAGgAaQBzACAAcAByAG8AZwByAGEAbQAgAGMAYQBuAG4AbwB0AA== Encoded with a custom alphabet (still using = for padding): !@#$%^&*(){}[].,|ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstu E&QYLh@fLVsWLV^c(&]QKVoeM!== |EAXJG[PL*)eIm)QKB@SHFodKm|= |D^DJ&Ui(*@hKlMhHFjPHl^dKVsj Encoded single byte (a) base64, second encoding is skipped YQ== AGE= AABh Encoded single byte (a) base64, second encoding is skipped YQ== AGE= AABh yara-4.5.3/tests/data/baz.yar000066400000000000000000000026401501365277300160360ustar00rootroot00000000000000/* Add padding for making the file large enough to trigger issue #884 pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading pading */ rule baz { condition: true } yara-4.5.3/tests/data/c6f9709feccf42f2d9e22057182fe185f177fb9daaa2649b4669a24f2ee7e3ba_0h_410h000066400000000000000000000020201501365277300267350ustar00rootroot00000000000000MZ@p !L!this is a PE executable $PELtU` @PP@  PAUTO@ `.idataPD@DGROUP` J@.bssp.relocV@B.rsrc\@@yara-4.5.3/tests/data/ca21e1c32065352d352be6cde97f89c141d7737ea92434831f998080783d5386000066400000000000000000013000001501365277300246500ustar00rootroot00000000000000MZ@ !L!This program cannot be run in DOS mode. $-d~d~d~{~d~d~d~{~d~x~d~B~d~d~f~hD~d~B~d~Pb~d~Richd~PELH @pT`^<.text `.rdata@@.data(P@.rsrc^`` @@@CÐVjC^ÐVD$t V^u Eh@ YÐEjhCdPd%Vj+!+h|D(jjhFD$DŽ$thhChPCh Ch!3PDŽ$WL$ vD$ PDŽ$ L$ Q$u,L$ DŽ$3^$d ËNUWjvVRLCjL$QL$XG;|h(DL$`C Łd;|T$jjRXIjjj'L$DŽ$s_^]$[d djhHCPd%VlC ujjhDH^L$d Ëfp HZD$D$PCF L$xC QRPCtjjhhDzH D$P_L$QCD$ HL$ ^d ÐdjhhCPd%VlC ujjhDG^L$d ËHzD$D$PCF L$xC QRPCtjjhhDG D$PL$QCD$&H%L$ ^d ÐdjhCPd%VlC ujjhDG^L$d ËH蚟D$D$PCF L$xC QRPCtjjhhDF D$PL$QCD$FHEL$ ^d ÐdjhCPd%pVjlC ujhD:F^L$pd |ÍL$D|C xC C L$lC D$hC L$pL$D$|T$`D$d腐T$hD$lL$`xC T$d|C D$pjC jjΉC C !$L$D$|2L$t^d |ÐADÐD$AD H jhʶCdPd%Qjl蔠D$D$ tIL$d ËL$3d ÐhCÐCÐV%HC^ÐVD$t V%^HC%D$P0jh8CdPd%SUVW3|$PwMd C|Qh'YȉM3;ȉEtuMd SVW|$fGtGPVt$YFtPWRu_^[Vt$tP8CvtVy~Y^USVuWVfF]+3f=f=]MFtFeuE~8uVa}NuNf9{u E+MOuЃ}u E 3ujXCSuV fuGtGf E ]EEEuS}uCuCf8{uE)+VSu萀u fGtGfE EM]uE M _^[SVW39|$t1p ht$V0CtPV,Ct P4CjXtt$Wt$P_^[ UMSM3ۋ;ujX9Vu;Wu]VU} 3fxE;UI] M]Mf9GGfGGEf=vUtf=ztf=wtf={t f=xU 4B;U u2tl}ujujuC3E EtԋEt=uMWPVuuu{؅t }t 6SCSC;Eu ]e}39],9]tuN4;tSMV E_^[ UQQW}G4@,EVO4EPEPEP 2hEt:u\fFftP謴p8o\Eu\‹Efft7PvN8MF8jF8uP}R^G4@,Et/O4EPEPEP rgEtP }u_ѽCAxSW}39]GEt>WfUWUfW fUfWfUfWfEfGfUfE}MW GO VwE̍EPEΉupUĉMC} u]r!m vSVCۉE)] 3ۡD]Ef}z]]]]t f}{ EԍH;ˉMf^mFEF=u0EM VE贺EjY]@+Mt,j5YEЅEtSuu/Z3eE}wE3)E EEMQPf8{uCCStu EVofutfxEf]#9]MEP3f}wuPVGPEPE7SPESH4tcMj{"EjSSSSu p CEM쉈EPE6EfMfEMEM܉9]^t uCE;tX et趂MM裷M_[d jtxD3VD$tV^VD$tV}Y^C*uQMDe%Md t$ 薸A ËA Vt$軽D$ f fx D^VD$tV|Y^x DVt$nD$ f f D^VD$tV|Y^ DË DUQVWu5CjjuwօE~(M S\SFuSPuw֋M j[M |E_^ VD$tV$|Y^BCsQVu "DEeN aMNaM^d VD$tV{Y^CMsQM"DeMd ËD$Vf fD$ FFPC^V VC^VW~WCN_ff WC_^øCr SVWeu^SC~ u16eFvPp_NIɍD|AV F +Iu~ SF CM_^d [ËEPCjj)wVW|$ tS^SCF S~ C[_^Cr4SVW} eMeWuS3;u3E;t,?;|~ u NNH39P3Ƀ~$UU+‰MHtYHt6HcvEP;w Ewt u։E39EGv;t uփeEvE;EPt u։E39EEEP7ge}t\jEwPvE@EPyM؃EQO1PuE؋MЃ DMfHEGMQPEPjV:(}EEȉEt6uxY+E @ t uP+M8E J@Ë} }}Gt MtEGEM_^d [ UMSWPfF3~;u^E ] PjSC;ÉEE]PShu  C;ÉE|EuPQEEPQE PQ9]P0PSE XC;ÉEt!P@C;tu PR4uyt1WF$pCt ?tN$VN$a_F$`8^VN$tjt$ jv(P tjXFjt$ Hjv(P ^UQyXVqXu*ILtURhFDQ| juA>tuuuuu uV^UE @t% @jZf;ujXĀt%3f= JVWu1E}3WPPREuVX_^] UU MRuuuuu PX]jt$t$jt$QP` L$T$Rt$t$P\øLCQQQMSVWUeeRuu P\EME_^d [ËMSei@øXCEQSVWejv u|Ce ~lMQj hΉ}EPd}u}Mj@ËuejMXQPhΉERdf}uMME_^d [ËM虙?j@ødCPSVWejv |CeeMEQjhPdf}uMME_^d [ËM1j@S\$VËW|$#Fl #FhFlut$#Rj hVQlt ##ut"#RjhVQlt ##t$WSv Y_^[ UVEW} ut##RjhVQlt !E#uWuv Y_^] Vt$jhVPlut$jhVPl^pCO SVWeeuMjhPdM_^d [MeӗMuEjhPdl@ËM诗5l@øCNQDVEeURu uuPCuhCMMvM^d CJNQDVEeUREMMp/M^d ËT$A(Q(USVY,W}쥥EMM} 5CPEQWPS֋MSt)C +CPC+EPWuS֋ESS@PPQ u_^[UQS]VÀt jÃ<tTt F,EF0 E EEEtF4N8+F,+N0EMWWQPuu_@t jE?t@Suuuu Pv C^[VWv 0CD$ tt ~jXjPRT_^CL SeVWUeRj hEPdME_^d [ËMFn@øCt%"t &PQFt fPQ^VWq 339>tWWWVjPQ>_^VW=CFtP׃fFtP׃fv%Hff Y_^U4SVWFH$c}w0Cj@[EtQpCP MMQpTCEPwTCES+ESSϙ+PE+E̙+P|j^}F~HWhp'D@LP|\~LWhFDSPQ 9EuE@9]9]t&ES+EMPE+EPuuk|MS|EFURh'D@LP;EURPQEPQE;u@g~WhXHDPEEPQE;|F?N QhHHDW9]t&ES+EMPE+EPuu{MSE|_^[UQQQHt AP#ËAu0AURh'D@LP|/EURPQEPQURhhHDP|E3øCC=SVW3F9~HE؋FE'FLURhFDPQ;ljEEURhGDP|BEU}RhFDPQ| EVXRVRPQEPQEPQj>EYE;lj}t ud3MFPEPQNPljE;Yt8xxx xx3NPFT1QNPFTAFT@ FPCNF QWP<NP +NPMF;u3URURhhHDPQ ;\h8IDP|EhJDPΉtxE}ElEMW\j(E}E }ERjPQ;}EPQE܍]EE3SE}ĉ}ȉ}̋QQPR;ljE}EPQEċMȉFEЉE܉FEN4PQ9~}~>3jmCYE;Et j #3NMED $E(;F|ċM;tZE;~J$EMEX;tËjpRE#E;tjPE(MuuCEM_^[d øcC:VW3u>}~uEV$M}}}}M_^d V"jPQ| jj^UQQeVUF RURU ҉EJRujPQuW}_^SVW33NYvN |t W |G;r_^[ËAVt$WPR4Vq 8PW_^tQh8DPøCI9 SVW3e]؉}uMQhXDV};ljE}EM;tPQEO{}{ueeMQhHDVE}EePQESRS WRPQ |΋Ecet PQCC ek4PE@YE @Ë]؋E3;ƉuuEM;[E܉u;s C4vƁxw fx t3YejEL@Y @Ë]؋Uԃe"zLDuC4vfD0 CD0CfHftfu@CRƋxσMyWQuHjQHQfHpQpu{CE4M,EL0u} ;u j} u?Yp@ucEY?YC @Ë]؃e{u!ua?YEMtPQ3uu3s uu+?EMtPQƋM_^d [C6QQESVeWeu&FP>Y @ËuM_%^d [USVuWM} F$juuV@W@PQR~6l>4OYu_^[]UUEVW3j@^tp H }0fP0Ux} P2Ux$} P3U$8PUP(U(p_;щH,HH HH^t @PU,;tHP ]ËL$S\$ VWCACtHtHtBCA2s=YDPCL$AtsPFQYYjX_^[UQQSV39] WSuP9^Ht}39^~g^TGEE E PtE K@3PMwEuP4YYۍMvuJ};~|E39^~FDtMPQn4YYt G(;~|뾋NuL$NPF3;ÉE ~=v~$3ۋ@;tЋ؋R;UtuA(;M | SL$_^[yVWt)q 3vT$ I9t G0;r2!:At$ I PL;w+‰_^|$Vtjt$ Pt$N1!Pjt$ tP[^UVW39~HtP9~@St99~8~3ۋF@PCG;~8|~8~v@J;vEEM;|'~t tEf98u QMCu*jm؅}EMtPQ1@uv6vv MEtPQƋM^[d fT$ 3ɉfPT$H HL$PH D$D$9A tA AUQV~tptj@LURhLDP|$VER39V RvPQ EPQ1-t&N j Zt WPRv9QWh_^VN u3^ËF jVPF ^ËD$ t tA;D$t L$3 D$0qD$0t$ D$t$ 0 t$D$t$0t$p3jh8HDt$ tjhFDt$ t@L$ D$PQ3 UVuW}jVuu |76t.t)t$E u tuOt tP3_^]jL$t$t$t$J|3UVuW}jVuu &|%6t tuOt E tP3_^]jL$t$t$t$|3jL$t$t$t$|3UVuW}jVuu |Dwt9~Du3t.t)E t#ttFDfDP3_^]UVujuuu 5|,vt#E tW~DFDΉ~DP_3^]U$EVW,ti39U vbMHw@$i@B$;U s@jjjj jjj^MjEωEEPuE3_^7@+@3@'@;@#@/@@jXjh8HDt$B tjhFDt$+ t@L$ D$PQ3 U$ESVW(E 3+t*Ht"HtHtHuAj[u3Rjjj[#j~DuFDfDPjME܋P]EE_^[ U(ESVWj(E_3j+Éu]Zt(Ht HtHtHu#}EE UEEj+Yt+t+t u j[jߋ;u9UuPJ;u}t }u6u1PMFP H ~DFD ~DuPt&jMEMEEP]E|3_^[|$ VulD$ptaFPNT0(NTAFPNT0FT@ 9Ft4vFCFPCFv QjP 3^tPQVW|$tWPt$ tPQ>_^QCËL$H3ɉHH HHHH T$u3L$u3AQPhr`CVt$jVtjjhv`CS^SVt$3ۅWtD=|Cjv%=@u+;t$t%vCP"jvשuu_^[UVt$WF=CjPPH"l$u2vCP1"PUfth;tdFjPP"t΋vjVP"Sjv|CtS\$t v0Ctt-sRu"SVU!l$u(CP!uSjV/[_^] D$H8tt$FtjX3USVW}u 3WtvjVwCPA!t#C;u t<uVYYtNj_^[] u WK؋jVWuVhYYu;uVt$QtF8t @q tjX^3^UQSVu 3W}]uVW9tFVYtjvwCP t!!Qu;tuE}|3_^[ S\$VWtN3x4up8upCP$ u߅t%u!CP ;tP_^[Vt$WtfvCtYv5CPtDx4upGHt1p t%L$;ttqp,Cu jP\_^S\$VWt$wMu;jPS;t*O;D$tjVSt ;tދ3_^[Vt$N8t t$ ^jVL$ Ƀt3j9D$Phv`C^ËD$uËH8t霹jP0Vt$ Wtjv|Cu Vt$ jjt$t"jVMYYjVt$t;u_^D$jjhp`CfKSujXUQeSVW}u3G]Ps,Ct jw|CWYEE ;u3E tKSfPS8t8;t4VYt)Vt PYu t }tWSE0tjW(SPSV YtMt jVYY_^[ CSVWeCP Eu!EHMMu!MIM܋M Y]rv tP=C~8u!vP;EtvPuمtF8t@Ttu PQttu7t3v8t,E f@f= u uf=ut3gE 0E3j-u[+t/9uujCfu f~ u ;}t(VW}uuxfNf uujf ujXVWutN@8tGVu WNM IJA  u EpCt"5CP;EtP PYu5Cօt6CPPuYYuօtPPuuNjM_^d [ijC3ftPEWpCPyVwVumYY%&(+uQYt uIuuSuJu PdC~83PPPjhVEJMj_M Uܮ@Eu uvQEt@uPEpCPn)x8Pd떋L$ɉH`DVD$tVY^CO QMDeMd ËD$}=uvPVVOt$VCP^USVuWgftWf} VuhCPVC3hCF6$cVSju3fPP`CSCGue_^[]f|$ uf|$f uf`fHfL$ffHUf} uf %f} u}f uf`fH fMH]T$uыD$;uf;tPjRQCPVt$VCP^jjt$ T UQf}'SVW!f} j^f;f Eu2Mjd[uuf}uufue3f9uϋDhAdPd%XSVWe|C3Ҋԉ:Eȁ :Eʉ :E:Ej%KYujY0ujY3uGCQEF:E3DuCIuЍEPCCEEtEj XPuVVhCPEP7E MPQPAYYËeu)=:EuKt$KhDYYÃ=:EuKt$KYhCVj>DMvYtVYjaMY^VD$tVY^̋T$ L$tG3D$Wr-كt+шGIuʃttGJuD$_ËD$jPdPD$ d%l$ l$ PU=OESVWuu uLYYj6Lu }YfGM PEtue 3GЉU fFPEtu3 3Fȋf9] u f} tj,Lf;] YH jLY3_^[]Vt$tV{@PYYt VPLYY^3^áDthDhDhDhDjjt$  jjt$  Wj_9=;Eut$CPC|$ S\$=;E;EuDhAdPd%SVWuNEu;j %JYeV]LYEt VPyLYYM}Qj TJYÃuSj IYEEPEPVmY E܅tPuuY M }uu j IYVj5NECMd _^[̋D$ tDT$VW|$ ׃t2t :uRFGHt8uENW8u;u_^Ëȃt+t'NW8u8u 8u8_^Åtċ8uHt8uHt;uH_^5DhAdPd% SVWNEuCu;5NEj HHYeVMYEM Etmj ~HYÃuZEtpj^u;5Ew.j GYEPXYEM Eu-Vuj HYËEujX$Pj5NECMd _^[U EVWjYP>D}EE EEPuuuC_^D$}UWVu M};v;xur)$x@Ǻr $@$@$ @@@@#ъFGFGr$x@I#ъFGr$x@#ъFGr$x@Io@\@T@L@D@<@4@,@DDDDDDDDDDDDDD$x@@@@@E^_ÐE^_ÐFGE^_ÍIFGFGE^_Ðt1|9u$r $@$@IǺr +$@$@(@H@p@F#шGNOr$@IF#шGFGr$@F#шGFGFGZ$@I@@@@@@@@DDDDDDDDD D DDDD$@ @(@8@L@E^_ÐFGE^_ÍIFGFGE^_ÐFGFGFGE^_ËL$f9At f@@fu+HU=OESVuu uXYYvjCuYfftJPEtFFt 9M t9E tFjCY3%jCYFjCE Y+#^[]S39OEut$ t$ XYY[Vj8Ct$Y8tUW|$8t/PEt:uH:Nt8XHt :t@8u8uPEtF8tF8u_j4CY#^[Q=L$r-=s+ȋą@PUV395OEuu uxZYYRWjqBYMPEtQAt 9E uq 9E uAujBY_^]ËD$PE@t@jt$t$t$U SeVW}wu=E~jP'[YY hDÊAtFЀ-uuM+uFuE$wjYu$0t E 2t }w u,9uv'E"tME$ƉEtEEtE؉EE E t83_^[jt$t$t$jdYUWVu M};v;xur)$@Ǻr $@$@$@ @L@p@#ъFGFGr$@I#ъFGr$@#ъFGr$@I@@@@@@@@DDDDDDDDDDDDDD$@@@@0@E^_ÐE^_ÐFGE^_ÍIFGFGE^_Ðt1|9u$r $@$@@IǺr +$@$@@@@F#шGNOr$@IF#шGFGr$@F#шGFGFGZ$@ID@L@T@\@d@l@t@@DDDDDDDDD D DDDD$@@@@@E^_ÐFGE^_ÍIFGFGE^_ÐFGFGFGE^_U EVuEEEu EBEP& MxE EPjQ%YY^ËD$jPEX@̋L$tAt@u~Ѓ3ƒtAt2t$tt͍AL$+ÍAL$+ÍAL$+ÍAL$+US39]VW9OEuuu u^V jt;Mu }YfGM PEt-9]u] PEuxBu] 3GЉU fFPEt}t Mu3 3Fȋf9] uf} t%EMt3tj8;f;] YH j$;Y3_^[]UQMv^feW3}fM =OEE _u3jE5QE5OEPE jPj,tf}uEtjXÃ=E~ jQSYYáhDHSUVW|$=E~jPmSYY hDAtG7G-t+u7G3ۃ=E~ jV,SYY hDpt \F7Gσ-u_^][t$lYUQMv^feW3}fM =OEE _u3jE5QE5OEPE jPj+tf}uEtjXÃ=E~ jQuRYYáhDHUjhp>DhAdPd%SVWu v3#NEu_j 8Ye}W:YEte;5NEwVWPB t}M}u j 8YÃuj^u j L8YEEPEP}WG E؅t5e;5EwVPuusKt}jEPYY?M }u0u j :8YÅuj^Vuj5NECEEMd _^[Ujh>DhAdPd%SVWNEuFj o7YeuV9YEt v uuM }Uuj 7YÃuFj $7YEEPEPuF E؅t 0uuM-}uuj5NECƋMd _^[Ëuj 7YUjh>DhAdPd%SVW3EEEE;E}uUu uEEMMd _^[}uuuu uUjh>DhAdPd% SVWeu EEeMx )uMUEMMd _^[}uuuu uUjh>DhAdPd%QQSVWeeMxM+M MUuYËeMMd _^[USVWjE5uY;OEY]u3pV3ҸD9tt0B=DrEPSCj^;!j@%QEY3PE9u󫪉OE}MA;PE@ej@Y3PE4R(D;t,Qt%;wUDPE@;vAA9uE}rEOEPOEDOEYQERAAyGƀPE@=rSYQE5OE%OE3OE= ;Etj4Y_^[ËD$% ;Eu ;E%Cu ;E%CuDhAdPd%(SVW]3;uu Yu ;u SFYNE9}܃j /Y}S1YE;;5NEwLVSP9 t]8V4YE;t*CHE;rPSuSi1ESP19}uK;uj^u u VW5NECE;t#CHE;rPSuSu:1MZ9}u";uj^u VSW5NECE܋E;9=YE܅t*E;rPuumWuu=]}uSVj5NECE܅t=E;rPSu&WuuT=VSj5NECE܃M&E;uf9=DhAdPd%SVWuu u uw3;uj^u 3ۉ]NEuA};=NEw|j *Y]W>0YEM9]t^uH3ۋu j *YÃuA;5Ew9j n*YEP:YEML9]tVSuj 9]u>Vj5NECE9]u'9Y03ۋu j \*YËEMd _^[UVu>}3E=~X= }Q+EEEP=EYVLHYE)EEPYF VVHYYt+E+EWjBEEEPYt=O }(x ~"EEEPYEPYt j EY_^]ËD$SVW03 }3@uj$YG@(;EtO@ƿiҀyF3;|+B;|+B;|B+j[ƉQQEAiuEQjX_9}@QHAj+D$QQ _j<ƿQ_AiƙAk<+a 1_^[UVuW 9>t E@ft~to}uijVuu V~ tP8csmu,9xv'HItU$Ru uVuuu Pу u uu$Vuuu P jX_^]UE e@E|M;A|SVucsmW 9K~ub9~u]~uWxl&pl@pjVEEGYYu9~u9~u ~ua9~9~}EPEPWu u؋E;E9;|;{wCEC E~dF@ xE~v7u= uM9EME}$uu$u S7uuuuu V ,}Ei}t jVqYY_^[À}u u$u uuuuu V UQQVWxht!u$u uuuu uus}EPEPWu uE;EsO;>|C;~>F NHtyu&ju$u VjPuuuu u ,E_^VW|$ GtJxPtAt$N;tQR"YYu"ttD$tt t u3jX_^Ujh0@DhAdPd% SVWe]su};utU~;w|eGDt hSPpMu/YËeM}]uG4u릉sMd _^[ËD$8csmt37U} S]VW} tu SWu},uuWu,u$6uuWFhu(@Gs uuWu,tWPo_^[]Ujh@@DhAdPd%SVWe]]ԃeu FE@lE @pE}xlMHpeEu uSuVEԃeM:EԋMd _^[unYËeejEPYY3ϋu }E؉F}MHlrMHp?csmu)u# u}u}tPWYYËD$8csmuxux u xujX3UjhX@DhAdPd% SVWeMAuxkA`U | etDujvAYY0jWBYYFMQPYYutR]jsAYYjWAYYvsW# ~V뗃~]jsu:SAYYjW]AYYt~vVsYYPW fAYYtVjW'AYYtHv5AYt;tjFPsYYPvWFPsYYPvW3MMd _^[jXËeUjhh@DhAdPd%QQSVWeEtHIteQpRMMd _^[38E ËeLL$Vt$Qƅ| 42I ^USQE EEUuMmZVW_^]MUuQ8]Y[ VC@Dt:jtjYYt)V5@DCtVYHCNjX^3^ËD$@PxD@VW4C5@DCu?jtjiYYt&V5@DCtVYHCNjYWxC_^Ujhx@DhAdPd%QQSVWe3uj9p`tEYP`u jXËeeM>Ujh@DhAdPd%QQSVWeeDDtEjXËeeMIhh>YYU@D]@D]EuMm]E?DvjX3h`DhCth@DPdCtjVt$Pu?eYt,F=E~jPO4YY hDAuԊ EFFu^ËD$Et :tH@u@t*t etEt@H80t8uH@A҈uËD$(5DrjX3UQQ}utEPxCE YYMMHÍEPCE YYMU(EVPEPEQQ$DuEPU FP3}-3ɅQeCEjPuVu E 0^US38]VuW}t39] P3>-PvYY>-u-G9] ~PH E38]h@DM Q]9]YYtEF A80t<^Ky-Ad|jd^ÙA |j ^ÙY_^[]U(EVPEPEQQ$BuEPEP3}-E PKBEjPVu E ,^USVu]WFH}t;E u3Ƀ>-ˋ0`>-u-{FjW?Y0YG} ~DjW'EYvGY}+}t9u |u u Wu j0W3_^[]U(SVEWPEPEQQ$AE]p3}-E EPSWJAEH;|&;}"t Gu GEjPSu EjPuSu _^[U}et2}Et,}fuuu uN ]uuu u4uuu u]W|$ tVt$ V@PVV6^_USVu F ^@tfN$F F fe $ f F u"XEtxEu SDYuVlDYfF WtgF>+HNIN~WPSSB E 6tˋ NED@ t jjS@A FMjE_WPSA E 9} _tN E% F ^[]ULSVu 3WMFۉMMЉu N Mĺ}+ |xÊ@D3@DE$@3MEEȉE؉E܉EEà t;t-tHHtMMMMMy*u#EPBYE_M؉EQEˍDAe9*uEPYEMEˍDAЉEIt-htltw }MM >6u~4uFFMu e hDeDAtEPuP Fu EPuP mÃg8eXCHHtpHHtl fE0u }}tuEPfEYȉMu dDMENf8@@E M@}}EfE0u }fEEPt;wPPB E}2E)Zt2 tH<YEEEPYt2Ht+}tMEEeM`DEPugu>E59U~U}~$E]P^YEt}EEuEuHM@EPEWPHDut}uWTDYgu uWLDY?-uMG}WYiHHtQHHE'<+u `DMNt8t@+EEEEt\EE0QEEGEEt: U5EPHE Yt fMfME=M@E Et EPYAE t!E@EPt Y%YE@EPtYY3E@t|s؃EڀMUEUEue}} Ee9E~EE EueEEEME Et?EWVuui+WVu؃0u*9EU~]̋EM믍E+EEEEtM90uu M@M0E}]@t&tE-tE+ t E Eu+u+u uEPuVj *EPEuuPEtuEPuVj0}tA}~;E]xfCPEPC>YY~2MQuPEPOuEPuuuEtEPuVj }t ueYu Fۉu E_^[K@@8@@@@@@UM IxE Qu(YYEu]]VW|$O~!t$Vt$t$ >tO_^S\$ KVW~&|$t$WFt$Pu ?tK_^[ËD$@ËD$AQËD$f@UjhXADhAdPd%SVWeL;E3;u>EPj^VhTADVCtEPVhPADVSCjXL;Eu$E;u=u FX.=u FX=u FX=uFXvXjY~XY_`QYEFT u C^[ËT$ DVt$92Wt"u F < vF> wt< v^S39QEVWu5:E3:t<=tGV YtPUY;5:Euj 蛼Y=:E8t9UWYE?=t"U ;Yuj lYW6 YY8u]5:EWY:E_^QE[UQQS39QEVWuP;EhVS\CQE5:E8tEPEPSSWMEMP;ujʻYEPEPEPVWEH5:E_^:E[UMESV!uW} Et7} 8"uDP@"t)t%PEt tF@tՊFt&F8"uF@CtF@PEt tF@ t t ūuHtfe8 t u@8t7} UE3ۀ8\u@C8"u,u%39}t x"Pu}} 39U‰UKtCt\FKutJ}u t? t:}t.tPEtF@FPEt@@Xt&Ft'E_^[]QQTuN@u NNC|5OEC_^[Vt$j&hCf8MZuHj,PY;Yt0@8t9;uA8uj SP tttEP}Y[3j9D$hPCNEt6NEu hY uu5NEC3jXVC20XC00USVWU] E@EEEECs {ta v|tEVUkT]^] t3x<{SykVS讱 vjD1C T{ v4롸UkjSn]]_^[]UL$)APAPI]:Et u*=Du!hXWjYujcYj>YWu C>PYj Y_6C^]UE4DC]̋T$L$u<:u. t&:au% t:Au t:au uҋ3Ð@ËtB:uA ttf:u t:au tW|$j$L$WtAt;u~Ѓ3ƒtAt#ttt͍y yyyL$ tAtdGu~Ѓ3‹tt4t'ttljD$_fD$G_fD$_ÈD$_h@j5NECNEuËL$%NE%NEjNE NENEXáNE NE ;sT$+P r3UMSVu AW+y iDMIM11UVUU] u~J?vj?ZK;KuL sL!\D u(M!!JL! uM!YM] MS[MZU MZRSJ?vj?Z]]+u]j?u K^;vMщMJ;v;tcM q;qu@ s!tDLu&M!1K!LuM!qM qINM qINu ]}u;M\ щ^NqNqN;Nu`L MLs%}uM DD )}uJM YJꍄ ED0ENE NE5CH h@SQ֋ NENE PNE NE@NE@HCNEHyCu `NExuiSjp ֡NEpj5NECNENEȡNE+ȍLQHQPٺE NE;NEvmNENEE=NENE_^[UNENESVWu;NEuM; NEu%NEMB_^[áNE NEVW3;u0DPP5NEW5NEC;taNENENE NEhAj5NE4C;ljFt*jh hWC;ljF uvW5NEC3N>~NEF_^UQMSVWqA3ۅ|Cj?iZ0DE@@Jujy hhWCup;wtƍ4;sCu0jX^;uCF;sN;Euq )u 9U }ƍ4;urq;s~;Esvu@j^X;u%C@;]s +q aq16;s)E 9U r4맍;]s +‰A aAFk+3_^[UQUS] V W}e+G ;M|vE+ȈG`seE4;wU;s 8u@;uBE;w+;v';s338u@<tC cC+MEE_^[á4=E;tPVYY5=EV;@P萙 ;ã=EVPMWjV5dEydE`>-uEFVY0i E<+t:|<9F>:uNFV貧k:u#FV臧Y Eȉ E:|<9F}tى EEtjV5hEhE `hE WY_^[Vj Ct$ j ^SVW39=Eu3Lt$j[F;pEu ;E9=1uBW@PWV>_^[]U(VEWPEPGYEYuPjj fu}FEډE؉FEPW ~ _^UQU SVWfB%#ωE Bپ%ۉut;t<(!3;u;uEXfXK<] ȋE M Huɋ ٍ XߋM fH_^[jsYVt$;5OEs@΋ NEDt%WVt$t$V(VE_^? = ^Vt$WVxYu  -t$jt$PCu4C3t PnY΃Ƌ NEdD_^Vt$;5OEs@΋ NEDt%WV$t$t$V(Vm_^g e ^USVW39}}}u3fENEE4D0 tjWu @E 9}E}M+M ;Ms)ME uE @@ȍ+ʁ|̋+EjPWP40CtCEE;| E+E ;Er3E;9}tbj^9uuLO M0A4CEǍMWQuu 0Ct E}E4CEu荥Y,D0@t E 8ޥ8+E_^[=Eh?YL$At I AI AAAAaËD$;OEr3Ëȃ NED@áNEVj^u;}ƣNEjP`Yt>EYu!jV5NEGYt>EYujY3ɸ8Et>E =E|3ɺHE4NEtu AE|^=;EtËD$8E;r=Ew+PYà PCËD$} PYËD$ PCËD$8E;r=Ew+PYà PCËD$} PYËD$ PCUSVNEWVpC=lC39NEtVjYj[u uYE Yt jaYV׋E _^[]UEu]Ã=SSYt/PD;Yv<8=uWSP tӋD83_^[U EeHSVHWtgHHtFtAt<t*tHtF<>E<>EB8>E8>E5@>E@>E(%vPuYY4>E4>EjEuYu}SY3;u9MtjYj'Et tuVTUNTuIVXFXUu7 DD;}(IVP dD=DA;|}tjVY}u vXjYYuӃ} Yt}uE}FTuEFX3_^[ËT$ DVt$9rWtAT>A>A>A0?A?A?A'@A@A@Au@AA@AUES]VȾ#fWEEEEEEEEEEEE?EtC-C } fuu9}uf#C CC0f;uzf;u}t@uhEDFftu }u.hED;u#}uhEDCP.YCYenhEDCPYCY‹ϋiMfej NfUkM} EEPEP f}?rEFPEPYYEf3t}}~j_u?feEEP]MYu}ށ~ EPnNYuOCɉE~PMu}EPEPEPEPEPEMe0EMuEHHH5K|0;r89u0H;s@f*,CdE_^[;r 80uH;sf#C C0cjXӋL$V; OEWsXEtA@ t PYtC|)t>E PCt>E4pvt>EY$G;=NE|^jY_[Vt$V#Yt^F @tvY^3^SVt$ 3WF ȃu7ft1F>+~&WPvL ;uF t$F N Ff_^[jYSVWj333Y95NE~tt>Et_@ tYPV.t>EYYH t0|$uPYtC|$utPYu t>E4V0YYF;5NE|j|$Yt_^[U}u3]5OEuu uuj5QE8u]Ã]QSUV5:EW3;tNdCWWWWjPWjӋ;t>UCv;YD$t/WWUPj6WjӅtWt$xFY;Yu3_^][YÃUWVSM u} Ej_u@WTADPWPSSCt=X>E#WPADPWPSSCX>Eu;~VuYYu9]~uuYYEX>EuuuVuu uC;9] u_^[; j,n;Y:Et߉89=:Eujn;Y:Etĉ8+u=:E}VuYY|C?t>t24<9lY?t GFPu荆YYt<5E2uz}ލPWeYY@M d:E} tFu z@@P]mYYt.uV Y+EYE @#SVCVkY3V5:EWt-|$WPt$P u 8<=ttFu׋+:E_^Ë+:EW|$3Ʌu3_Ã?Gt AuSUVPlYuj gY߅tPiY&^][_Vt$;5OEs8΋ NEDtWVFV(V _^葈 菈 ^Vt$WVYt<tujjY;YtVYP`Cu 4C3VƃYNE dt W蓇Y3_^Vt$F ttviff 3YFF^%|C%`C%\C%C%C%C%C%C%C%C%C%4C̋D$u33f .REQPpCVWt$ Vu,D$u=]E @<ń\EW3f.REPVhC_^̃3f(REVt$WP=pCVׅ3f.REPVׅ3f2REPVׅ3f,REPVׅ3f0REPVׅup3f*REPVׅu`V uS=%]Et+VCu D$jPVCL$hEQPCD$ PjVCP3f.REPVhC_^̋D$L$Vt$WVh>EPQR C d>E9N uwh>EPlCf=@RE_rjF P|CD$uD$D$N PjhQ`C|$tl>EN PQ3h>El>Ed>E_^ ̋D$L$l>E d>EHCP E̋D$SVWt$PVL$$T$ \$QRSVPtCxC3f.REPV3f4REPVӋ_^[Vt$t PC^VdREVpRErhpRE^̋D$Vh!pH +΋@Q+‹L$PVRQC^̋D$ %SVWU DRE|$$QWTC\$(L$SkC Qifl$4A D$@fD$tD$jjjPjjjWCC D$D$@fD$tD$jjjPjjjWCfD$0f9D$,t DREQWTCCD$HfD$tD$jjjPjjjWCft3D$D$HfD$tl$D$jjjPjjjWCVWTC]_^[̋L$T$VWqyA rzf|$$B fǍT$f%t$PjjRV}L$L$ L$D$$D$(WjjQVZ_^̋L$D$PQ\CL$ T$D$QL$RT$ PQR|C̋D$S8VWt$tK= C3ۊ&u@8u-58%]Et#: $]Eu@8utu @8tP@F8uD$ L$PQhCL$P$ QP`CL$ $ T$$$_^[VhREChREChRE$REC=$REut$jjV. t$.tV RE^SVWU3HChREC9-|RE~o9RE4uSREHREt D$9REu8REPlC |RE;-|RE}REGE;-|RE|E;-|RE|hRE $REC=$REu ]_^[̋D$jPf=@RE VWs3_^= REu3_^t$thREC=|REHC39|RE~RE99@;|RE|WD$$<u4l$,jC+j D$(jl$,jPS;V|$ tRD$$jD$0jjPSD$8L$@l$@D$XjC+jD$(jl$,jPSD$XD$8|$tBD$$jD$4jjPSL$Dl$0jC+jD$(jl$0jPSSWC|$\tVC]_^[D̃SVWU|$u%\$(l$$D$ St$UPWVS]_^[3t$f4REPVpCl$$D$ U\$,PWVSVt-tCP]_^[PtCD$ujV|CȀuD$]_^[ËD$wtHt#D$]_^[ÃFtQCrDvX݃u tuSjV f=@RE s|$ ujVf=@RE rUV뇸E]_^[̋D$jL$PT$QD$RP̃ SVt$0Wu$D$@L$EøC/QSVW3uuS_&D]F\jLSPED/E pF9E~E$1E E QQ@$SuhpDV$V82E nt2Ht#Ht tt$E j ^E;|EtE E u W7EYW1Yuumuu6(7 jKme_^[L$D$ Pt$ VhFF Pn؉F^ËD$ Vt ~ u~tt$ FPt$PCD$ F^ UQEhDPE6E{+UQEhDPE 6Eb+ DøCd&QVWu3WuF`jBWP}F\!D%F\ BE N\0A9=9EutF\HN\9}zAA*N\A.tF\F< pH@F\F<pHF\M_`^d VED$tV .Y^Vjj[D$!DF\^%Cw%QVh-YȉMet v\3`NPHPM@< p^d VWW7#27t jP_^VWN\Av\l΋tjX_^VF\pp N\AF\^@UQA\e@ uMhDdP@CQMfEUQA\e@ uMhDcP@CHQMfEUQA\e@ uMhDcP@CHQMfEA\Hq\nÃ|$SVWt!t$=@C׋\$tS3u32PFPFPPC5ۉEt(;;EtPXjP3ۉubjX"YE3;É]t n؃MjuujPjjhs`C}j,EjPG EEEE(PjhEs`CuEPjhs`CEH@E܍EPMwCj,EjPK ME(QuuPdȉEA#9MuR9uJG%t-EPCEM Pjhs`CuSEj Yu}%?MEy$t EE3PVhs`CE@u M<t@Vjhs`CEx$tEPjhs`ChVVVVVsCuuST(rWjhs`CEj E䉆Yu}}u>Yjjhs`C뇋ufG$3%t;tf@$u pCP;rvr wjX3G%uju`tXtPtHt@t8 t0t(t tttuP-M_^[d 3ɉH HHHHL$+DHV4D$tVSY^VW3N~ ~~~~_^øCQM+DeMd V~u/j FvPjNIIɍD|AVF IuFNL$HL$ F `^D$QI AuIVjvL$HNtFF^AVp҉QtbaP^ËD$V;AuQP02;AuPQprPg^D$uAt H;L$u333DHHH HVD$tVY^CLQM3DqeYMd UE SVWtF}3;uvgY^^ ^N;u%SSjPF~ ~^ ;%F;~Ѝi?RjPK ̋Fu#FjY|;~}jX;E |} E P؋FPvSFi?ύQjPvE ^~F _^[]Vt$W;w| FjPGL$_ ^UQSVuCW}E;j| 7PGƋPϋCi?MQ Q 7PO KPjQ'NtǍNSu 4Iu_^[ T$VW|$F++tNP:PP )~_^D$D$ PGYL$ tV1QUYu^Ë3ɉHH HHL$T"D@HV?D$tVY^VFt PfYNf ff^øTCrQMT"DeMd V~u/j FvPNIIɍD|AVF IuFF N``^ËD$QI AuIVt$3qD$ Itt 9pt3^VqWt#|$ 3ҋqt9ztB3_^UVW}EPWu/9Fu jvxNU NU_^]VqWt2|$ 3ҋqt9xtЋ0P2jX3_^D$VW0uQ3vA0uG;r>u(FSY3B;sA8uB;r[D$ L$8FL$F_^ 3ɉHH HHL$0D@HVD$tVY^SVFt PfY|$\$ tWWMWjPF_^^[UV39nt3S39nvWF<;t OQ?C;^r_v%Yn[Nn nn^]øCQM0DeMd VW~u1jFvPINIɍD|AVFIu~jhDF FGPcg _^VW|$ 3tk!ŠVF3qD$At4tFWPYYt63_^UEPut M @ jX]UEPuyt M @jX]UQVEWPuRu?9Gu jwuENFQGMGM4F _^|$u+t$PhCjVYYt jX3CVW|$ W^$uu2t xPt3mu\GtuOj7|CtAhC7/t1jvxCt PtCtjjhv`CjXWB_^USV]Wu} uWSuXtuTǀtOsGvCPtuuWSR uC tuuWSR tjX3_^[]V8j F_}P_^VWR8t3FXt,VLt 9PRVW Pv@VR u jn35t&F%t jjvCPt D3_^UQQVWϊ39xu3;考;ǾFtMQWWVR tjX蚊@MQWWVR _^VFLtP|9 v@ 9t j6u j3^hFdAtV΃PCjX^Vj`6t j[^jRVW@wHGDtSX jw@S0CPS,C[t P4CjXt7f~u N fFfvfF fv fufu fujX3_^t$ t$ t$ 4 Vt$ uAv0Cu9|UjSvVz jjUjSv%;~P>vTph0C9hu NUjPU39l$_^][QSUVWL$P(3;t[\$C;sUUPv;u*6;u4FUUWP;tH ;KtUUWs L$sPjX3_^][YVW|$ ?u Wtu|tFWP`*tjX%t7' ";t W3_^L$Auu j1,C3V较xt$u#}uutt$VRp!hT1C5E蛔t$t$Vp0 C^ D$Vxu7xpu1@ @u&5Cjf|jf|jf|jX3^U SVu 3;WM(E+tuHHt -6 ;t\";tO8tD9_Pt?{M9Yt2Nu~ tuShFhp`CH{=9E3s;tVtShFhw9]uvE9X tnF=rd=w]hT1C5EG؃uCj}YǃuN ;tMQPXt jX 3_^[A uAu CP V3WP~0PPWCt&~4jtWPXuWCWCjX_^ËjY3҉HPP PHPøCQMAetPMd UE SVj[tMMHE(wqt\HHtS tFHt>t.tHuiEM0pUEM0pUMUu EMUu -EM0pu Ug)tOt>Ht HtHt3RuMUCuMU:u uMVU39^ÃfuMVUEM0pu U؋^[]UE SVWu!u8uuWRu{]e ϋC0EP,t\} uVwFtH~tB} u<9Eu2}u>t%tjPu" u FE C 뱋?렋E Wt E uP(t1uu Svu6upupu uW3_^[]jX3J @jȋ~@jȋø@Cø`CøCøCVj őP t~j t jP^øCøCË3CH HHH$HH HHHVF t&~u|L$ɃQvpCU|$Wu@~C;Gu2wCP2NtIjQpCP7t$ N7_F^VWF t#~uLL$ ɃQvpC/F=`Cjjhp tFjt$hp_^VW339|$ QP9~ t59~u09=9Eu o9=9Et59EF WhvpC_^VF t:~uCNWWQpCt$ f% vPF vpC_t$Fp艗^UQQSV3ۋF;tFf=t@W}S^VjPR 9] Et9^uMQVSv]P PE_jX^[63ËL$@D @DVW|$ WoYu@DtWЅYu_^t$YhCC3E jP3E hAYL3Eu L3EP3Et  j3EhAYL3Eu L3E3E6  j2EhAYL3Eu L3E2E  j2EfhXAAYL3Eu L3E2E Vj FjPC ^V D$tVY^VWI~j jWCD$ _^Uu u|CM# M;u3*Qu uCE3;t PQQQQQuCjX]t$t$t$jt$t$t$t$jt$Vt$t$ vTC1L$^ UEVugu1PuVEPvTCE ;Mu?@;Eu7jvCPt l3ut j&^ UQQSVuWS1@uAM}؋A;t*FEu!}GEEPu hns`C_^[ U} Vue}t}t }uJMt>pCPt)CP;t2tvCjX3^] C4SVW5EehT1C裉jY}C4e]M u}EC(r-CNN$jjhWF~ `C uNE ^_[] VN8u.vTCHQL$ P.PvXCL$jv. t$^Vt$ W>uvC@tVR jvUu_^UE VPE p0tE ^]D$Vjp u^UVM tE PtE ^] SVt$ WvHC3~9WvLCPi?tt$PuWvPC;D$t G;|3_^[vE?Vt$ W>u@hT1C5E|O9HPupTQDCP>vP^t)VRvjVwg t ju_^̺C0SVuWEȉePv$v]SSuWP _^[hT1C5EQs;Ft Su tjX;u3U SVu WS\CEFhT1C5EE r;Gt uStjX$EMjQM NEQuωuP _^[ VWt3At,=CPPtuvߋ3_^Vt$VtW\t'@"jV|C@t VC jVC^tAu3VVtPV^ÅVtqu3^SW=|CjV׻@tVCt jPV_[^VWCP΋{pCP3;_^VWWCP~t@N;tQP,Cu wC_^Vt~u3^Ëu ztmt^UVWu uxC=(Ct.Vׅtuu Vu?}Vu1u(u׋tuu Vu jVC3_^] UVWu=(C׋ta}tVt$uuu pPuuu V`C}tVׅtuuuuu VjVC_^]UVuPhuu tjpuv$C^] Vt$Phtjpt$v C^UVuPhuuu tjpuvC^]UVuPhuu tjpuvC^] VW|$ ut$jj_WPht$t  WvC_^=9E3s3:VqW|$ tWPhtpj_t$D$PWVCjX_^ =9E3s3:VqW|$ tWPhtpj_D$L$PWVH C_^ U$EVPEPuEjPu^tE3ҍHH;#)MEUSVWv0CuX9EuS9EuNCjvӋtPEPWTCEPJMU 3jPʋUPQMQPWCjWuuu uv$Cv4t}u u uPX_^[U$SVuًM 3;WEMEEt }॥ EPs\C}t jCEes(C3;tFV\CVR;}uu;}r;} w;tEPShaV`CjVC붃}u*9] tEPuCrEMHMXH \9]tI9]tDu}uU MJMJ)MJ )MMSQR`EPEuP9]t uDC_^[US] VWSC}E t?tqEPSTC5CEPu ֍EPu ֋uEVPCu9xu F$tЃ%dEjj_^V?V@t9pu t$M@ufjjp ppv^SVW @uFNt;=Cjf|,jf|#jf|jhFhv`CjX$_^[VQN;u 9E%] @ujjp ppv^UE VPE ptE ^]VL$t ju^ USVW=C!jVVEjPׅtEPCjVVEjPG_^[UVM E P.tE ^] USVW} ٍE PtE =h3CPEftvEvuWpu F_^[] U }tc}t]EtUtQtLu Pu mt:EPj uhCuuTCEujCPuXCjX3$C"$SVWeuMV[Qee}싏MNMQE'NAËuhj0΋PNAË}EM􉇸E_^d [L$`L$HU`SVWu EEtx8E@t vC jvCtjjhkW`CtTCEPvE@tjW|Ct t3E(u:Kt@MQjP\LPL5CEPEP֍EPEPVEPWӍEPjW'LPLEPEPC-vC5\C؍EPS֍EPW֍EjPSWCEȋMЋ}+}؋]++]܋ȋǙ+‹U+ȋE™+‹Ù++;M}ME;~+EE؋;u}u;]~ u+uujjjVQMj _^[SVW39|$t54Qp ht$V0C;tPV,C;u3P4CW_^[U(SVuمEW=CffFFfFFf=4Utf=u8f=uCf=uMEPjEuhf=tf=CuVjPPs׃ueu}t}_t3PPPPhdsE^[8ChVWMȉuzMv3}(C;SVu\CE̍EVE;tMWQhWu_MEWPjuouI] ;t6WWhu`C tMYtt t u3SMujVC;X[MM}M_^d T$B=r=v=r= wR3SUVWj3D$([\$|$t\$t|$vCN$D$zLC09|$tvWWWWUCug9|$tjvӉ|$D$$u9|$t9|$uvWh!t$(`CD$$uD$D$PWhjv`Cu|$R\te9|$t#E=t=ujvӉ|$Ppt<URdt D$|$WWWWUCuW)f$F,_^][A$ËD$A,A$t$A$3PPPqCD$Vt$WF$SML$@ =CQPׅFu hP׉FV_^ SVCWVhCV$C؅tShCS3dCuD$?#;D$u'ujX^SVt$Wt$vxCt P=N4t4t$PPt%w yw C9FtVjX3_^[VW7jvC'_^t$h2E.Rt$ I4t$ t$ PT A4ut$qxCP t$RpA4ut$qxCL$t$t$RlA4ut$t$qCt$t$VF%tCH8t$ȋVR$ t$vC^A8u jq|CËbpA8u jq|CËbtUA8uuu uq|uu uRx] UA8uuu uqeuu uR|] A8ut$qCt$A8ut$t$qXCt$t$A8u q\CËA8ut$jqCt$UA8uuuuu uqCuuuu u]UA8u%Et@uuuuu PqCuuuuu u]A8ut$qCt$A8u qtCËA8ut$qPCt$A8uqCPËUEH8tU Ruuuuu PX]Ãy8tjt$t$jt$Q Vt2~8u,vCPD$ H&t@4t V^y8uD$@4t QVt$ vݮtH$t 9A8ua8F8p$^VL$x|PpCD1^j@jP5EMhAøYù5EMj@h5ELhA葸Yù5ELj@h`5ELh:A_Yù`5ELj@h85EkLhlA-Yù85E|LSVt$ مu DhWj@_;5ELx=;5E;`5Eֿ;85EƍF PVYpd0 p _^[A@u Q5EL=uQ5E=uQ`5E=Qu85EYVH; DtPlC  D^Vt$;5DtVlCh^xtx|h5EVW7~~}vF@PV7V _^VW|$ x;x~DWr_^VH; DtPlC  ^UES] WËu E DVuPSEP6 ^_[]DS\$VWۉt6fu P!ShCtWWS6r _^[DS\$Vۉt SY3t#W<WGWS6 j_^[VW|$ WWt$6 x$8_^VW|$ ;t9y} ; Dux} PpPpC_^VW|$ u3WhCWPc_^S\$VWۋt SY3<WGWS6 j"_^[S\$VW|$t$PbWt$6St$,P_^[C趻QQDeVEEM j ^PupQqMMEPueM}ME^d CPQQDeVE}j^uu3 uhCM u PQqMMEPueM ME^d SVW|$tLxX+H9;P Wt$Q xH$t$WPpS_^[VW|$ u3WhCWP_^D$VPjk^D$VPpS^SVL$ xX;H~0Wx;}QGPC P62 Sxe_^[VD$u6hCA^$VW|$ W{x$8_^jt$VL$ ;H}L$QPYYu+^Vt$PsYYu+^S39\$Vt$ u;t3SSt$Vjt$$SSdC;~\0^[Ã|$ Vt$ut3^t$Vjt$jj`C~fdF^UVWVPuMa+ǃvMP338SMWGPKPu#؋+Ã~݋Mj|3[_^V<t$t$@ Vt$P4Cu ^ USVu WtG]Kt}WVYYt"FKuEPVxYYuVhCMs3+ƋMPVP P jX_^[]DËt$i|$tt$L$ tD$3øCq SV3W9A etEEQ EEM_^d [ËM5BÅt;L$tIjX3@ËL$Hy~ tjPUURhRP tuuPc} uE uuu cVW|$ 3;u FFWYPW_^D$VF@Pj@XCt@WP@Cvt$Wu fuG 6FM9E }}u5EQD?\_u\u;\t SͼY~S轼Y;\uE+D9E } uWlC6ShCD0;E ~S胼Y;\u$>5Ch!DWSW_^[ gCQQDSVWu^ DeFDF}E!DPYEEt h A8hF@WjPEXE3u FEE~F uNEMF_^[d V_D$tV蘹Y^S\$Vt$W~h A7jVYtWfY_tVNY^[CڰQVu!DNEtjNEeNMN M^d UVWuPsF3H~6FQPu FGH;|~F APxONP_^VW|$ F FH;F}LQ 5G |_^UE VAM0xu3MSWSpE@40WlCjjWUj^W+hCE;uJ >$8WuMEPC@EE>t!SPuSPWPC?Ext6>SQPE l+ލSPu PCuEpWMjjX_[^Cˮ$SVWuN G_xut jSvk:G39Au9CtSP j9F 39G~FN jPq@CC;_|捅PhCPhC DƄ\@EM3ۉM]9_EEjPPESPEME@PMt(&u@U PEtU @A@AҀ jMGj 3YDERh"DP8C EԍMPMEQPEPNEFuQVPPF hQVpCM$MEC;_F NpHCeMF FMMM_^[d UQQVWF@PܴYE!1@3WWv ȉE[9~~7S_Svu8CF <tMWuv U[;~|[u褴Y_^øC3 VWF@PVYE0@39~E~QSF_SPu8CF Mh5EuPEP+ePF MM;~|[uY_M^d VW=CjjF(jF,jF0jF4׋=CjF8jF$׉F _^SVW=Cj j F׃~hF t|CCjCCjXWjZWFWjFC_^[/@USVW/3C;H;ƉC9utB}t;t @T;tVVЋK KKKK$/xhT1C5E@taF tP=;YsKtBF etPv ENYYܭYF u9Et uǭYF 3_9C^[]CQVWj Nue~ jjjE "D~EMFw'tR$+!B3jj'wL w%tHtHHHpj ~j z!Ht#HHtHHPj^̃@$!BjGjCkwFtGwt9@t4Ht1Ht_HtHcPtHHttHtHHj Xj;wQtuw%tltvtHtHHjj Ã{oHhHa!;w8t-t( 8/t u^oj dj]-VtHHz HHu&-&HHHHj rB$!BBByB: BB$!B$!B$!B$!Bk B: B$!B$!BB BBB: B4 B4 B4 B4 BBBB: BB$!B4 B: B4 Bk BC; eVPDEj^MPPuPP=?jM MEPjueMME^d C蹘 eVPDEj^MPPuRPPjMMEPueMdME^d UePMPEUSVuWhjV蟗 Fhw PPCG;MQMQMQPu~uFFjX_^[U@Vu Wu~W&u PuC;u3oPCW$MFF PuWPMuWFPM|uF>u~uFFjX_^UVW}3Vu@VlfE~u@V@fEnuf@ VfE^uf@VfENuf@VfE>uffufEEPEPC=4Cu VPu EPCu VP_^SVW!Ht$xt$t$t$l:t;tt)PPuNtPXPhPT_^[Ajjjp`CË3CHHH VD$tV胝Y^CV~uH}tBShY[BjH!YȉMetjjhC3MSF[MF^d jt$VW|$ u3"jbWH~0vP jX_^VW~tj0t vHPf_^øC!QMCeyt PPCMd ËD$AD$AaÃaSV3W=HCFtP׋؋F;Ft Pׅt_^[VW=DCNj;NXtt$ Q׋vttt$ VׅtjX3_^SVWt$pCN=@C3;NtSQ׋vtSVP _^[S\$V3WN=@C;Nt tCPQ׋vtu3CPVPY _^[VWN=TC;Ntt$ Q׋vtt$ V_^V3WN=DC;Ntt$ Q׋vtt$ V_^V3WN=HC;Ntt$ Q׋vtt$ V_^V3WN=LC;Ntt$ Q׋vtt$ V_^V3WN=PC;Ntt$ Q׋vtt$ V_^VWN=XC;Ntt$ Q׋vtt$ V_^V3WN=TC;Ntt$ Q׋vtt$ V_^UQQVW=XCF;Ft MQuu P׋vt EPuu V׋EM_^MH UQQVW=\CF;Ft MQuu P׋vt EPuu V׋EM_^MH UQQVW=`CF;Ft MQuu P׋vt EPuu V׋EM_^MH UQQVW=dCF;FtMQuuuu P׋vtEPuuuu V׋EM_^MHUQQVW=hCF;Ft MQuu P׋vt EPuu V׋EM_^MH UQQVW=lCF;Ft MQuu P׋vt EPuu V׋EM_^MH UQQVW=pCF;FtMQuuuu P׋vtEPuuuu V׋EM_^MHt$q\CS\$V3WN=tC;Nt tCPQ׋vtu3CPV_^[SVt$ xCW3O;Otv vv6QӋtv vv6W_^[SVt$ |CW3O;Otv vv6QӋtv vv6W_^[UQQVW=CF;Ft MQuu P׋vt EPuu V׋EM_^MH VFt9Ftjt$t$PCt$ t$ vC^SVW=CF;Ftt$P׋vt t$V׋_^[VhHDhCh<DPdCt vЋ jxxC^VWhHDhChTDP3dC;t t$ vЋ9|$ t jxxC_^SU-CVW|$WvՍ_SvՋ@t _^][SU-CVW|$WvՍ_SvՋ@t _^][UVEWPvCEPvCuYPuu=tCYP6uёYPuǑYPv׉F_^UVEWPvCEPvCu苑YPu聑u=tCYP6uhYPu^YPv׉F_^CQVuEedDt@PFCPWuM^d VD$tVY^ĻC誋QVudDe8PvCMTM^d øػChQVuEeDt@PFCPuM^d VD$tViY^CQVuDePvCMM^d øC贊QVu^EeTDN@QPFCPuOM^d VD$tV赒Y^CBQVuTDeFPvCMM^d ø*CV~ uH}tBShY[BjH YȉMetjjhC3MSF ͑[MF ^d jt$VW|$ u3jbWH~wj0X_^VW~tj:t vHwf_^Ãyu3PCø;ωMu89}tVNS3;;߉]ux9}t]9}u9>~ EN[;~9|v;~9p|pEM_^MHUhSVW39~hZj[v^h]CPMz;t9MQWhhp`Ct"EP}M̋E+M+EȉMEGEPEPLu.EPv\C9}9}WjnEMuURURURPQq9}tE)E9}tE)EuuiuE}W9}t+ESEFLHΉEEPW7u SuWW耑uSؑ9}t+ESEFPHΉEEPSu SuWSE~h_^[UQQ} VW}uŞuPjjVC@tUFN ++NS_LP+؍E+MP~EF[~$EF yPjRPuC_^U}VtMjЕu%jPh9EuMju Q^] U}VtMj茕u)jPh9Eu3ɋmju ɀQ^] UE Vu jVt3uuu u^]UQQSVWsj؋_WPht Bu ue}jPht uue}39}u 9}u3}}tAE jxSPtCttN`ȋFX;| f} NX~ً3jQPE}tVE jxSPtCttN\ȋFT;| f} NT~ً3jPQt vLC_^[UQVWj蔎Eut2Ht*Ht"HtHHtHt Hu"3u wT +wTw\+w\jH3ɋЊM Ƀt2It*It"ItIItIt Iu"3E GX +GXG`+G`u+u+‹PVt}t wLC_^ UQQSVWx؋jPh3;t Gt u} WPh;t #t u}WoWΉ]ʎ]y3;~jJjΉ}褎} y3;~;]u ;}u3A39Et7PPE+PE+P貎;]t jSjŒ;}t jWj豌jX_^[ Vpf<^øHCgQVueM9u @NMURPdZt j@H;t jE)MujQh5 3jR_^[UQSVq3ۅt1WƋ6xϋPTEtMQPXtC}uu_^[øC]QVWu`D3}F`E~@FFt F<F<@MFN,MF@;ȉ~}F~,NF9~,Eu'WWWjPP;ljFuv`YF,~}F,MFN(tMF$_^[d CtXQVue~ t FubMNVM^d VW39~~ uv,`Y~,~$N8;tjPN4~8;tjP~4_^Vf ^UQQS] Vu3F$W~(+;sWPu\~$} +3v+e}N uuP4EE)Ev}w+]9}39~uEF];wEF,EN uuP4E)Ev }v;r܋F,F$ 8N(N F(~,PWvjRPF$~(+;sWPu%\~$ +ߋE _+^[US] VWۋtzF$~(+;sWuP[~$} +tUU3vN +WuP8}+߃~tN F(~,PWvjRPF$Suv$[ ^$_^[]VWFtV(F$;t N +jP9W(F(F$PF$V,S39^~,u;t5N +PRS8';tN US+‹)SPjUP]N V(RWvjPP[F$_^Ët`4Ë`8Uuuuu uP,]VW3WN諓FWpCNjWWWWh3E<_^VWj|$ ~!59EhC~$uhCj_^t` jXËt t$Pt$Pt t$P$u L$j t$Pt t$P03D$VW@PR|uWjX_^VttNht t$Pd^USVW3ۋS}EPSU3;ÉEtSShvu`C;t ;t;]tEE;t] uÃv vw0txhPj\CSWuuCtE}t juPCMj_^[ U@tuu uu3u u] 0CRQDEueMEuEVPu uMM輔M^d SCUl$ VWueuUuL3t PӅuu t VC\$tAt:WtCt/;t+jW;PC!ptjV|C@tVӋ#_^][NøECQQV񃾀u(j ZYȉMet3MuP M^d u3Ë`t$PUV~|t6utSWEjPjju VCV4C3_+uEhpDP8C EPu uTC^ Uy|VWtz} uu3zuV(CG}uutu VC'tuhC@Pujju VCV4C3uu uTC_^] QXV~I\3~1;t$t @;|^D$I\DUQQ\S]VW} M4D;t*3ǩt jj~MN j~vS_^[COQQESVWK\eD 4u} Fux u POYYtZe} ~t u  M}ujX F 5f F t3?N MWQhjXkB3M_^d [ UlSVW3ۍMSSSj1w`C5@C;É]t Pu։EEPutC9]tuu֍MEPCuEPKMQShuj+uCEMx++EL;}ϋE_^H[ DT[$UEVPCEjPepE M^MHMHMH 39AtT$3T$t j3PPPPP谋riU}+tuuu uyujX]VjjZ^VZjj^ Vj }jt$P~H^S\$V3W;ދu3;V|$O\@p;~sVPt$=R D$$F_^[VW3W;| N\Dx_^VYL$Nx^VW~vFm%|$ u Pvb_^VW~v;|$ tPv4_^jt$qIpU(VM'RNX3EبDuMEv8N\jMQjPΉEPPu PMuSE@;EEru u3^DV8UhFE 3ɺD;tA DrW}t<DtG?4DD]C33ҊԋCE0C ؉M u~^j}] CSWPECEtWuCu@CWӊNE3h PVjZML(Qu uPPu uPPWCuWWPCujCV~"EY_^[ Vt$ Vt$ hv^U$SVWM܋Quh} eeE܀wg g jPW" N\jjh΋p\juhWuhjSj7\G j[2Mu,t;Eu!MQuhtESPSjvXC_^[UEPuEV񃾄t)t$ t$ h^u t$CUQQQd%tt jFjUt jJjUjPjURUEPu=EM UEVPuE 8Eu 8Mt!EEEPu dž^USV3SShU]]]EE;M WEy GΉE YZu=LDGtE jYE GEet'G tU 7GU;E~2E-t Et PDE;E~E;E~E}tGEMG te}t] M/_EM^[MH UQQSV339u MuW}bߍBB t M ;M~t|  u@t xut8J}F|GT u9u BtztH}3ۍ3ۍL EDF;u O_E^@[ US39]VWEPEu uSu Eu;EtF9]~AEÙ+‹Vu u;Euu;t ;]|uu uu EuPouS] SuzSEuPI0hSϋ@uESSEuP"@E;}`ϙ+Pu u"u EuPMH9M}P;u9Ut0@E~Su u_^[U@SVW3WWh}}Љ};uP"YEsEuW6EG;|3;RCdȃMtiE u]E tWheE tWW[}t;EPCE ˃PEPu<E tM+MM+MPEQtWsTE W$%PVuVEuPE @@MЉE}EE΃E@t8tGIuP!YtO}3eeExE}E@tA8tQSVWud~|3ۋω]ESDFxF<wEPCM^H^L^D^@_^[d VD$tVY^wCQVWuD3E9~W t 9ppu`pG;|eN|M%M_^d UE V%@jFdJEPCjEuuPu jh(C%^ jXSVW339~W tCG;|_^[SVW339~$W ttCG;|_^[U,SVuEWPvTC9^pu"39} u EPC39{xt Fh@tKd@cdFdKd @Cdu"hP9NPsGNdCd3%39{xt $P9^p}t%v0CthWWWWWNEM9} t{u EPCEP!Eu+E+‹ȋE+EM+EPQˋu{ EE+EhMPE+EPuujNu3;{|Vwjw9E3hWWP9EPWMvCP;t;u3CPv@CPkNp;uWu;t9{xt 9yxujX3PjV{9}^ptjWWWWWW^MV9c _^[U$SVuEWPvTC9^pu} u EPC{xt Fh@tKd@cdFdKd @Cdu"hPLPs NdCd3%3{xt $Pɲjv\CP6~ 4} tsu EPCEP}9Eu+E+‹ȋE+EM+EPQˋuYuEh+EPE+EPuuj;}{|Vwjw 9E3hPPQ 9EQPKvCPn;tu3CPv@CPONpt jjVyˉ^pRa _^[D$SVWft p\CjP~,^|jW|u8u jW_^[USVWu u}u_Ep\CS4l~j~|jSo|uM8uHjSP<~|jSA|u8u jS"}t uExttF`~xt0u"Bu PXjXjLJ 3_^[] UVWuEu }PVCu FN ++N .MQp\CEM+E+M3E9Mt|C|9ES9Eu9EЉuuRu\MuGFdt tjX%$PEjPEċMÉ]EEЉEEEPvTCEP]}39ME;E~9Oxu+EQPEPC3ɋE;E~,9Oxu'+9EU+E+;Ӌ+EQPEPC39Mt9EMQMPEPC%E+9E9E|E;~9LEPEPCu79uFdu~tuǔ}uEP|vP$3]ċE+9E]9EEE;E~9Oxu+EPEQPC3ɋE;E~-9Oxu(+EU+9E+ЋE;~+EPEQPC39M9EUЍERQPMCEPEPCu79uFdu~tuǔ}uEP|vPD2E+9EEȉEЋE9E E܃}|QE+9E9EkE;`9LPj^VQPO|uu^E܅tW}t(+9EM9]M]9MM9E%+9E9]]E9EE9E؉EЃeEE;39[u9|t |DCEPCuEP(*9u t9uu9ut E+EE9u t9ut9ut E+EEEM_^MH USVW}E3ɥu E9NQPCVu%}u襥M_^[UEVPCFd%PEPW)E M^MHMHMH CTVVM|ettMQMML|M^d VW~dt$ ǀFd~d_^3V~;D$ t4;t$t@;|^SV39~.WS*tYjt$WfKC;|_^[L$f#U SV3WE^dE9EEutttfEPwTCEP xMUt+E+EH9Et+UU+MIMt M39M M39Mt( E3+9EMEE ;uE;E|DEEEE;D3M|jPyWjuW_^[9MuEj@QPN|EjuN|xWCEV~tFhu%h YȉMetV'3Ft~ u vCF M^d DÃ|$ r |$wjX1 CQVuoaejMD^d VD$tV+ Y^CQVueMbM^d øCQS] VW;Ȁ}LJt3Ȁ3Vuh6EPh5EVVbu jPw@f t&FtPC~ tjjhv`CNx^UE S@V3ltsuj^@M t uAM8duEj PQ -t=Ej PQ u0u%M t uAM9u t;t3M fM jX^[] U VuWu >t5Ej PWXCEPEuP"u/jPu}EPEuP8CEPW菞_^UE8tuM1hhDu Ph] \CQQDSVE3ۉE]uMjQEPdtzE9XtrMjQPdtaE9XtYu W};tE@PEBF$D1VD$tVY^dCQDEejjhUhRP,tw@uȋR|MM]5Md VPD$tVY^VKD$fL$ Ff$#p*DFD$F N^ CQVWup*D39~ }tMΉ~~~~mKM_^d t$GYt$t$YYL$ Vt$ W|$ ȋƒ_^ t$hYAS\$VW~;vC~u;s F;rF u WPT WPRX؅uT^ ~_^[VW|$ ;~vWPd;~s~~_^VW|$t NF;v3"9;v+V WRt$P\~_^VW|$t1F;FvPRdN NWt$QP\~F;FvF_^U} VWwuu} t } uwu} jjj Tw_^]VW3F ~;lj~~~t 9~$tPR`~ _^Ë`L@83US]VujXuE FF;FvF3pW} uF;FvPRdFUF uFN;sF M(u~+~FN;sN M+F_+^[]UhPu 7tuuPuUSVu 3W8t]%uAG<0|<9~tn%uOF<0|<9~t$Wdtv\C#_^USVuWVjjFw|CFEPwTCuE+u]H+]@;ΉMEtVGetPPQ+ 9EjEQPCEjPwXCuEV+59EjVPCEjPwXCME;tNGetH5CP+9EQPEjP֍EjPwXCS+9EuESjP֍EjPwXC_^[Vu >Fdt j.WvCPϋt VOl~l3_^V}g9u jNlt VE$fl^V~t8t8RX^Ë^V8ujX^ hCTVVMYetMQMMZM^d ø|CR4VWVMXeEPv\CEPvTCEPVEM=CPEQP׍EԍMPTEMPEQP׍EPEPEMPTjujv`CEPEP}MMXM_^d UVu WE PtE 4tv59EE59EuVpu Q9E_^] UV~pt.juu PduE PvCNtuu ^] V~ptjt$t$Pdu NtP^ SVWN`#33t ;t t;uj@Z;ӉN`tRSSSSSK tGNp;t t7a;tu ";tt$W_^3[jjOSVWlFd%# F`tDt t7u,j@Y\$339t"$QRRRRRvF`3C$F`_^[UVu MVE SFWPEPC}]+}+]M39VAd¨t tE t RUjRM;|ωME;|ÉE} t1VF; VtFLtDU+)FU7Pt/VN;VtN@t U+)N UU_[MMȃ>MtEPEpV 3^Vf`|$tuN`tN`^A`uuu3jXUVEPv\CEPuEPu^U4IdSM] VW}̃=9E}ܥ9Eu9EME etMMء9EMetE}Met+uMetu +EPjuj;39Etu jsPPt;E%Etu +EPjuuO;}tu jsuj5;}tr9E}E tP+EPjuj ;}tu jsjj:}tu +}Wjus:}tu jss j:3_9E^t 9E 9Et 9EK9Et 9E)K9Et9E)C [AdVW@@u_QHĠD$t&x p+yL59E59E++@Wj@VP$x0+yL59E@59E++@j@WPVL$$:_^QdD$Vt59E0t 59Ept 59E)p^t 9E)P |$t-Q@QHPQD)PQL)P Id@@u1,QHQ@PQL)PQD)P Id@@u@T$D$ ;}+ J;3L$ Vr;}+ r ;3QPRC^ L$4DHhQlPl3҉Idt Št@ @ǀAh4DHpt jjP1UXSVWǃ8Nt jaNChHdMQpTCEKhCE 3Cj UVRKhjUVRKhjUVREMUȉMMэ{(uEMUU؉EЉMUUэ{8uEMUUХu{HuučuUEEUMEč{XujCHVMQpTCEKhCE Cj UjRKhjUjREMЋUȉMMэ{(uEMU쥥SHuju؉EE܉u{8uME쥥{Xu॥VRMQpTCsxEKh։CE ҉C RUjRtĠt{|t3Pt{|u(CpKX@K\PQsX&CpKH@KL PQsHshKl,[U(SVW33ItW]IEPChpTCE KhCECEjUWRU܋uE؋Mȉuu{(uEMUju{8uuEMUhEEECHuMU쥥PC9EsHP9EPVPCS@F{DN +S8++{<+N++σee{XuEMuctu ˥Q_^[ U8ESVjKS+M +ʋ ^t" tj" ^uK,K4C4+C, uC(C0C0+C(}3KhWVPEPpCMQPTCsH}襥 _tY tTC`+CXEEECd+C\EEEEPEPEPCtrC8EC@C<ECDECPECTRCX+C`+EEEC\+Cd+EEEEPEPEPCtC@+EC8CD+EC_^][VWj>tCpCPUj4CƄtpwC&_^U$SVWjXjEEpCPHu+ECtut s(}ܥMPts8=Cj Hj!EHECxt{|t Pt {|tsHsX}܋EE39utuu959EtCutjEjPPC9s$EuEP{ uEs sWuuP*u܋E쥋MCE𥥉C 39M_C$^[D$VL$9t?FpĠtPt ~|tjX3F|t3jΉFt^QSUVWsx3#9C|t 3;;tKpt #PQs(KpPt_PQs8Kld'{|KpŠtH#PQs8Kl2'D$Cp#jPs(Kl'+D$#uTKpPtL_j#͍s(QKl&D$Cp#jPs8Kl&+D$#_^][YUEVĠWt URPq(Pt!U_RPq8Ilm&E3_^]USVW=0CׅFhpHCP5P-;Fh3SSESPCE-t^HtF-tHHHHtsEPCVM9UQQĉPt6/9t'Suz9t jud}tP;FhX3_^[u9tZjXָCQVuDerMM^d %6E% 6E6E6EV5|CWֿtf=tօuf=uh`DC5E%5E_^øDøCQVWuZ3j Nl}觶DN@FXPEtDF<~D~H~hCΉ~P~L~TM_^d VD$tVY^!CQVutDEEO9u 8OtP.YEeNlMM^d VQph0CbVH]^VPph0CaVHz]^VPt$@ P|C3ɉFH^VqHtt^VW|$ G=t=u7kWgu?Nht WPTu.G=r)=w"tWPvxCtjX3_^tjPVNh^t t$PlVNhtPptjX^ËU^ÃUV39nPtWSWgjWWvD$ PCCuUUWv0C;FutCCUUnPhjhPv_[^]V!xPt59EhCjX^ Vt$ Wu'8t tO@t jVjX3_^t3SVW|$39HPtL9L$uFFt>G;t5Et-W=`CQhevׅu PShvjXt$t$_^[D$9D$t PtjX3QSUVWjD$3pC=CP׋VtCt0V"t&D$VpxtjjhlV`CuEjV׋uPDYj3pCP׋tQVtCtAVt7D$Vpt&jjhlV`CuPVPC4EjV맋$_^][YV񋎠tZIɉwStI8t1W34Ctj48PC<u_Y^QUVL$jpC-CPՋttSCWVtSD$@;tHVPt=jV|C|$u%=u!jVӃO$uG$t jVӃg$jVՋu_[^]YSVW|$3ۋ;tF$tSSCvCPuv;u9uXN$HF$`CUt%$ΉF$nC;u jjjUF$ ]tjjhv΃ W_^[SUVW1@t D$ -`Ct@L$t t;tN%jjhwՀf%jjhwjpCCPӋt Vw{tjt$hmVjV_^][Vt$~(ujF(LCF Āt=9Et@F =9EtN-jX^USVW339}t$VJu@ PhC;u Uu < E;txu$EHSWx @++WPQRuu uu lutSlC3jX_^[] US]MV W 3;t)Su MuuuuuQhPVVPTu3&959Etvt j VQM_^[D$t8thPptjXD$0PVtt$ t$ u#jhhbvCj3^UXVWHM @ QPCtWj0EjPE MEȋQP\}t0H@MQuPP`EtMQPd-;u}uP|SPX_^[VW ~Dtv~DDC;t WvdCnE@t9pujjjv4Cu_^Vjt$ qltPª^HCQQSVWBu]e;tuuu uR tjXPW_F^VWt$ tjPVjX3_^C9DSVWEu 3ۋFN;lj]uFdu=ut Q\C;t*hPQtLj jPEP9~jPuFPuPC EhSSSSS6Cj[MMM_^[d SVt$ j[F-t1Ht'Htt^9=9EjXu jXW>PC#ËP_^[VK0;uL$39VPRP D$@^V=Āt3Nht Phu#|$t tpj^UVW@tm}=CtIuPlCF@~$PhlDPhCP8C hhDPPdPlC}tK=ChhDPuP׋F@~$PhlDPhCP8C PvP_^ SUVW3ۉD$9\$ t Hh;tSP\np|$$;\$t{ŋmXs\C=D$rV=wOjXˉD$$tD$$ D$t |$tGj#D$(PSHu3ۋD$9\$ GGSΉ7-xCvSPD$(CvDC;ÉGtjSvXCSvdCFHhyGΉ^H9tSvD$ h!jPC-xCh!vՅD$ t%SvՅth!jPCSjt$(CtjjvXCwvdCD$HhtjP\j;t PvՉD$ jt$$CGjΉFHi_^][ D$Vtt jtPvLC;tP^ËUVW39Sj[t]$9}t Nh;tPP tpWEEEPEPShSW}}EjPFXPjhSWfMWQP`Ej+EPE+EPWWWSFXWPjhhW$[_^UEVHtNHteHub39U u 9QXAXu9Pu 9Pu9P t&PC;u qXVCu u VC33jRu jhhRjX^]V蘺|$t j^ tjXnUQSV5CWjf}j[3jf}jX3 CpCEu!Eu  Ph w`C3} u Wh V`CVCۋu t;uu_^[Vt$Wu!w0CujwCtj ^VtVV_^D$t$ttttqCPXCV"uFl^VtFx^ËFpt xxtjX^3^VWwuAt$ Wu#_^9C辫QVWHDLJhDE#tRvuDhYȉMet j+3vMVQWu$#hD|M_^d UQMSM VW}u1Wd3HD3t F=hD|4DDM uWS_^[ USًM VWud!M DD6tEjp\CP4'MF3Adu 6E dD|uM uu_^[] UQSVW}3ۉM9_ltWwp;tP9^xtK8u?Fd#Et4vCP蹷jSSuu SjGdtMEPt E/ EuMjSSuu S9^ uGF hKSWjjw|CtjvLC_^[Ue@S]VWt#ypt~Nj?p΋tv0CtڋFd#Etσ~xt@tōEPvTCE+EuEE+EuEEPEPEPCtt3Fd#E3_^[6-39H,&-L$H0-@0hH:EHhlCYL:EUQSVWtJv,C}"tjP4uWP4H=CjXvjZv 9E9Eu=tCS SE6uSv׉F_^[UQSVWtJv,C}"tjP4uWP4HCjXvjZv =9E9Eu SW6=tCESuv׉F_^[UWj>=H:EuG3ҍEʿUUBf8@@|EPjjjjdCtWCWH:ECj>5H:EL_øCҦ8SVWM@0Du3ۍM]+uMEuuE8CPMuEPCEPE PEPPCuEPEPCEP8CPMSSSSCPMEMj#EP#MQu4C9] uE 9]$uE E$Mhu܍MEYűuE;SSSSCPM8v vv6u0CEVPCEPEPEPPCEVPEPCuuuuu0CEMj#EP#MQu4CE M$@;Au4SSSSCPMEԍMj#EP#MQu4CE M$@;AtP;tLE܋PwMQPPu$MċE+M+EhIZPQuuwCVp9]ЍEuEP#MQPPu HMċE+M+EhIZPQuuwC;tVSDu̍MEu܍MEuMEuMEuԍME M_^[d Vt$ vTC3PPPt$jPPvC^UVuvTCEUM E‰MEE3MPPMPQjPPvC^D$VWt$P0x t$@++WPRV_^ UQS] VuWMuFjPSug}uMGPjSuOuEMWjSP:uMjVSu&_^[h\:E^BhX:ETBh+CHY`:Eø01Dø"C蒢QVuDeE2D+M^d VD$tV蟪Y^4C,S399E@j 99\:Eu:&@ hyPCM\:EQjPhCtEP:EET:E9X:Euqjj@j4Eh5C}Y3Eu 3E4EøDøCQSVW}jG3Y;ÉM;to9_u;jSth h 19]j$誌YE;É]t 3@|Ft^tn^twP|F;3Whhp`C;}9WP|%|@SSShR u .9^u]ME_^[d C貃 SW3ۋ]2;ÉEt EP2;t SSjSR 9]u9_|VhDMw|M]EhDPEPEPEPME1EPVEPuV,C;u2hPSu0C=u EPVGu4CEPPuVCM]MM^MjX_[d t$t$0Cs E MVQPu,CSW=0CSPVu׋uGMP!uEPuMEM }uSPju_[tuE 0u(Cu4CM^d DVWv|觃t$SF|芃vx7_^USVEW3PVWhdDh]}}} Cu:EPEPWVWWWs|$CuӅuEPEPEWVWWWu9}54Ctu9}tu֋E_^[UQQV3Wu[;u3%EPEPVhVVVuW$CW4CE_^UQQy|VtFuuEHEWPEPEPju EVCV4C_u͋Euu u\C^ C 轉W39y|}u #;ljEuu DSVM M5CQMWQW}uP֋;u)EM PusPEPWuujM u4C^;[uME P uMMM i<9}uE5EhPuuu XCPMME_d VW39=9EtjXh1C9E9~upF pYAFYAFZAF \AF`AF _AF$cAF(\AF,^A!pV u~ ~~~~~ ~$~(~,F9~u3 pV_^øDËDVD$tV^C~QVWuDetPXtjPF0=lCtP׋F,tP׋v tVYM_^d hT1C5E<ht=C%vYù5E3ҍ<PP P$P(QLHQQQ L$D@(@ PH@0ǀ@VD$tV^*C|QVWuDDEtjlltHRP tjPepM_^d Ë`` D@ T@(AVD$tV ^|QSVuDNej[tSNtSNtSN tSN$tSN8ty teP7YN8N0tSPN4tSPN8tSPM^[d hu?C$tYù5EhT1C5E @uh?C5Eph0CVF PlCu"Ft PQfFt PQf^Vhtj tjxD^3^VD$tVV ^5CzQhYȉM3;ȉEtwCMd øDø Dø DøCnzQh蜂YȉM3;ȉEtYMd øDVij3XDFH9 9Et N@NDNL F@FDFLNx^VD$tVMY^CyQVuD3PPEMM^d t$ t$ jt$ UEVW%N@ NNdMӵth-EPCjEuuPE PjhD_^=9EtAdЁuf%Adt$Cx,Wju }S39]EVSSj1w`CSMȋ};]]t Vu@CE9] \]wEEN;Ét;P艿t^URHQPuCE܋MFSPu`(t1SCjY9]FuNEE;E |]9]^t uu@CMM(}jjE[M_d SVW39~XF\~X賹G;~X|t$t$t)F\39~X~XjhDS| G;~X|jX_^[U S]Vu S莙裳tHvCPTCu4MWQjh=Cj׋sj++u+_s^[U(S39]VWEPvTCEPEPEPCEjPJMQSh}F\+}؉]^X}~@tEjZ++UIu$eMąۉE~A^\ECCLt~ Ǚ}M+EEMEE;FX|uvXh39] t&9^XF\~xGt j7S%C;^X|e_^[pDULDu\SVhChCh DPdCؾt.jEjPu EEPӅ| uE 5LD^[áPDuvSUVW3WCh0DWWWWjWWWhWWWjHCPC-@C;tVSՋhPDj6j6SC;t VSVCSWCPD_^][V3jFxF|X<DFHFLdždždždždž^VD$tV|Y^$C1tQVu<DePtjPfXM;M^d UVWu uuuOu%@}$Gdu Gdh脫gEPCjNu$ u EuNPVjh DWt"HjX_^] VHt/F tjPh%jjhjX^UVvCtKEM W=`CPjh vE M PjhvjjvXC_$EE EE^]UQQVMp huV0CtPV,Ct P4Cu3~FSWPfzef~YvˍFEV@@9U|FMPS)SPzYt'NFqQMPPVRuM _[^SVW6p jt$V0C؅tjSVOPu3 jw|_xX_^[U4SVEW}PjWhC3;u3EMPEЙ}MPEhF/EEЙUMRMQh.Ή}EtSs;_^[USV3WSShHtxSShOujESP/p}M ;9] ]]~n;EEu.E踬u=LDGt EE EE]EMQjht[EE;E |SShjFXX_^[39] E~ыMQjhtG;} |3ɸDøDøCoQhpwYȉM3;ȉEtRkMd øhDø Dh#j6EghKCgYù6EDh!j 6E|hKCgYù 6E DËQD$V14^u39Vt$3;u A0 tIW<;tׅu_t 1jX^Vt$j@ CuG^|$t t$0CV3FFFFFF FCuGFPC^VWtP CFtxjPuFtPCWuj4}9>uUMjM_^d [js3WW^nUQ9tEEE}t MjË T7Et t$t${=P7Et P7Eu T7Et %T7EÃ=9EVu4j^59E|C<st59E%9Eh7EC9E^Ã=9EtD 9E=9Eu5SVW=Ch7E׾7E7E>tS9E|_^[S399Eu]99EuTVW|$97EC47Eu)U7EUӃ>u7EPCUC]7EP_^[=9EuD$@7EPC 9Ehh3SCf`Yù9E7^=9Et&V5Cj@j9E@9E9E^V5Cjj9Eփ%9E9E^SVW|C3jʉNT<NXY@3+;ÉF\N`Fd^htSC=@Fh贻Ή^$f=pChShSF<׉F@39^\^P^D_@FF^[øCfQVuCFetjЋvtV CM^d øCfQMC9Eet @tЋMd h1C9E}hTC^Yù9EhTC^Yù9E("DUEPCPCjX;E9EjmYt "D`3ø"Dù:Et `"D3VD$t V:E;^|CfeQM"De諽Md ø`"Dj@j:EhUC]Y:Eu :E:EUSVWueYVhCtc PVYEYPVW,CuB3hPSu0Cuj[u4CuVW(Cj\VinYYuVfYjX_^[U}Vu$u hCPu juhC@NEPuhCu6u hC@Pu jjuuCu4Cu ujX3^] CcQVuej NLM0$D^d V4ZD$tVlY^CcDSVEeEE@MQP^W#DËpDEEEMjQEPdExMjQPdu EMPEuEh#DP; uMjQPdt Exuch#DEuh$DP;uh#DEuh$DPi;uh#DEuh#DPH;uaWEuh$DP+;uDWEuh$DP;u'WEuh#DP:u MjQPdExtoEܹPMQM諧PVhCjMuE9ptuPaYYu$uEh#DPt: uuME苣MEMEs_eM^MMRM^[d ø@C)a4DSVE3ۉE]E@MQPFE;WEċxEЉMPMVEЍMPEFEЍMPE6EЍMPE&9]tnDEEuȋ@uP C;tuȍEh#DP>9 V(CSEh#DP#9 E̍MPME>DEEEMjQE PdE9X|MjQPdu EMP'SuufK9]t(uEh#DP8 Suu9MSQPdt5E9Xt-h#DM9]h#DMڤh#D#DEVuh$DP8Shx#Du9]tsVEuh$DP7Shh#DuyVEuh#DP7ShH#DuiN#DMV7VM.VMh#DM#DEVuh$DPf7Suu9]tRVEuh$DP87SuuVEuh#DP7SuuMjQPdE9XEPMQM躣PVhCjM;uE9XtuP]YYu;SuuBt+9]t&uEh#DPn6 h<#Dh8#DuME胟MEwMEkME_MESMEGME;E9]7_M]#MMM^[d "DøH*Dø+Dø+Dø,Dø-Dø`.DV?fj3YFXjNDN@YF\Ft"<\tDVD$tV^>DhdCNYù:EVt$t PQ&3^AtPQÃQpCV~Fu3^WPlCuP_^ËAtPQSVt$ WVPDP898HDu@F;t,MteURuPuEu ϋ?u3_^VWt$ t$t ~3t$ s%@_^Att$t$P t$t$QC&TQVj V\Yuetf\8D3EMFEh(DPuX^UES3;tSESPhqSh,Cu E3u uuPCu0CjX[] U9E uuuPuIE)9E uf}cujhFPu`CjX3]Vt$jIN\^D$A\t3ɃIIVWt$~`j,jW9DRD$ |$,Fdt FdD$ FppgC_^VD$tV[Y^9DFUQVWFPt@MQPVFhdF`Pet`}t juPCjX;t8uu dž$vtwu džWjX_^VTD$F45DFD$f f(F,D$ F$D$F045D^VD$tV ZY^CQQVu45DN et~0t v$YYMTM^d VN(;N,r3FPF$Pt$hV F(jX^A(Q,;r3@;‰A(Ãa(øCPQVj8*YYȉM3;ȉEtPv,v$vN(^H(Md ËD$HD$Ht$ D$t$ H8 CPQESVWx̋Eet ] ue]E}t"VPPtwMM .jCËEt+]39EEME_^d [COQEeSVp̋E WEe}tPTtMM 辘:kCËM39E_^d [D$H̋@PX3COQEeS] Vp̃#WΉeEP\F tG w G PpC4e;ME_^d [M kC t%(CVh(lC:E0NthLDBP,Ctf3^ËF^øCNQj,ȉM3;ȉEtGMd A ËA tHA USV5Cj3jjESPօtj[EPCjjjEjPօu^[UV8DjPPEjPCt}t }uE@t8Dr3^jX{CMSVW3eVVVu\Mu\E&uEEM\ME_^d [MvQmCøClMSVW3eVVju\EMu\EuEEM\ME_^d [MmCøp8DËD$HD$H t$ D$t$ Hl UEW39xu9} Vt} u'jWVVEWPCuWWVHCPuuqG3Y9]EPC} tu9]tEPUj GYE;É]tuSS3M9]=CtuN_u9]tuN Ju9]tuN5u׋EhDFEFEPu@C}f;f t&WESPEPC;}EPCVǃwg$}CEM̈VEfMfJEM̉MЉH:uuXuC$M3f9]}uĥEM̉Med _^[zC9{CzC$zC7zC$zCNzC9{C9{CzCzC9{C~zCC{CC{CyC9{C9{C9{C9{C9{C9{C9{C9{C!{C9{C9{CC{CC{CC{C9{C|CH}CH}C}C}C}C}CH}CH}C,}C<}CH}CP}CP}CP}C|CZXY $+ $YV39P;u3)D$WH H5Y^øCS6QVWu DNxEڡtmW>Yu>YNttjPthjpCPhC7CeNx袡M#M_^d VW|$ W&u I Nl_^C5EVWj++HPE+Nj=C+HPV׃}u2jV%N F+N+Uh( DRQPj蛾_^[ut$t$xt t$t$C/VWj CPM試ueEP,M܋QPPEM+E+Mh!PQuuvCWEDjM^uM_^d C.hSV39sp9s|W}EPwCE܉uȉEԋEEEDu5CjPjjxCPMeEDjEP3jVxCPMu@9u}CxKxPEu3GKtPREAUI\I;wKpPstCt5Cj p։ECtjpu䋋$PjjQCKt$jPqCPM|4uu0u tEPaH؉EԉM؋jP4u؋MuQP8jEjP軜jP$EċPv vv6wCE̋P™FσPF@PEP5F @PF@PpF @PPEPF @PF@PI}jEEmmpCuPEPvCjP x}@\9@;GWQuKtvv1KtURjjj PpKtEP!vEuEEE܋EEEuKtu Kt KpstKtPCxuKxP E(;}M1}KtPCxuKxP uv HjPM/M'Du̍MEučME_M^[d tt$ t$ t$ $ U샹Vtuu uJEHHtjHt>Ht4HHtHj@\@j@\@pju jjj ^P\BR+3҃ @jj ^P\BR+3҃ +Rj@ jHPY^] VWjX+|@jω_^Ëj@PËjHP&@jhhp`CUQQSVuWtEPvȋIN} 'v*v6PCu;r3_^[ ʋL))NtpRtC?tpvtCjFXUQEVPE P"t!u3@uu uP^ T$9tt$t$t$:tV33VR@VP^ËV3;t 3VRHVP^USV3W9=CSSv׋@\fHfs@+Ev]ujv9]tKEj_SI\IM΋@\@EEPW}NuSuuWJMjMdžS<T8 P T8$P$T8PT8PPRStCt|7u wE 7uӋ M ΋RPu 轷_^[ T$VWI\I;v@\@9s39ujjK9|$t"398vS3ҋA|(;r[jWvXC_^ C&TS]VW} D;E ^#@E3DEej W@PEPmtBuSEuP8C u ESuP8CEPEjhbp`CMMgM_^[d  Cf%QDVWEeuHMBPUl}uϋP u$jX9t I\f9Aw 9w3PMMfM_^d VWL$ t>@\@;P_^VL$6v\v;P^SL$3ۃS[SL$39S[UQQ} Vt/1nEPCEPvCt8E PEPdt%>ud@ hyPpC6hjpCPhC3^ PEVWh3Cι39~ u%WWWD$WPCt R\u39~ _^VڧpH`jT>^Vh3CPEZ@ ^SVt$ W@\fHf;HvfH}x39^u:9^ u59^tF8t*@\fHfH@\fHfH6Ot^f@\9Xu8Pu9^tF8t6u7A\9Xu t$@\fHfH@\fHfH@\9Xu3hDNF\ijX_^[C",SVWM}3ۉ].fxuXy@;t?xu9H P@SQRPCMI\AE@\9XujShEMQDEċEE@\@ F9]=hEMchFMEchGMEchHMEcSuEjuuSREETtNtEbEFMEbMEbMEbEME荍PPMEcMEbtE wbEME\bMEPbMEDbME8bDEG_[^VW|$ u3*Swv@CP誊؋G9F,t ΉF,D[_^VW=TC~tt$ v CPvt$ v_^VW=XC~tt$ v CPvt$ v_^VWt$ vTCj΋ _^UQQEVPuu vXCEM^MH UQQEVPuu v\CEM^MH UQQEVPuu v`CjEM^MH UQQEVPuuuu vdCjNEM^MHUQQEVPuu vlCjEM^MH UQQEVPuuuu vpCjEM^MHUE3+E9U vM9B;U r}@EE]UV5tCWEPw֍TPw֍EPjh/DwCwCE܃EtEPwCM ẺM u,S]3҉]9UEEUUt-}u E ERRjh.DwCM 3EEU9<3Ҋ3:E;ʉM9Ut< PEt Eh*MQPPwCVPPwCuEUE+t)E;u,Ut+™++FM(E(PEtM(CE(EE[EPE+EPuwCE+EE}uuu$u uP ;u,u+MM+MNEECESEYM؋E;M EU+[EԋE0 uEu E+uU}tju1wC+u,EM_0E^M؉H,3Pt$t$PPt$t$R`4C E SV3W3;ƉeuuuW9uujXEuPYEuvYEMPEuSVVVVPuEPEPE]Puuuuu uwC9uEt3;t/wCt"EPwCEu+EPEPuS EYYM_^d [uYtC3ܸ@Cv(SVW}3;e EljMPMYW]tYEMMQSPEu$Ή}u ujPuE PEPSuujjuu P`SKuCYYt/vCt"EPvCEu+EPEP EM؉M܉HuEY `uCËEM_^d [ UQQVWuuu uvCEPvCjuuvC_^t$t$t$ t$ P\ D$#<"}h}^|#~T ~|~@~ ~63=|=~#=~=~=t=~= t$t$t$PqC봃|$VS^8WSvC~0WvC9~$@};~@} ;ȉ9F4~(N4@}V<;~@};ȉN4V<؋=CjXvPv59Ev3jZvPv59EvvM >`D1MM>M >M(D̍M>M>McD̍Mq>Mi>HD̍MU>xD̍MA>EM+>øD̍M>M >ЀDc̍M=M=M=D?ulZø8D*̋MsT`D̍MyM=MXMxMMbMxMxD̍MxMY=M MxM鲢MbMxMxPD̋MpxDk̋M\x@DW̋MHxMpT}hD5M(xD#uPYøD̋MMx^fD̋MՇMx>fDuYuXøHD̍MiMXxD̍MhMhMXMXDg̍M;DS̍M;D?ulXø8D*̍MM;M;M;M;M;WXM{;XMh;M`;MX;MeM=;M5;`D̋MDw̋M ;uWø0DW̋M:`D@̍MmD+̋M D̍M髃؆D̍M̍M9D+̍M˂ D̍M9HD̍MpD̍M9DuVøD̋M D̍MkD̸8D̋ML D̸Ds̸Dg̍hlhDP̋M D;uhUøD&̋M M|KD̋M M|+D̍M l@DuYøhDMzUD̋MfUD̍M -8DuTøDn̸0Dc̋M0UDOu|Tø@D:̸hD/̋M 7M7M7uYøD̋M 7M7Mt7D̍Ma7MY7MQ78D̍M=7pD̋MrD̋MprDk̋MqM fDID?̋MEM :pDM2(pl~ʹع,Hb|к޺$2BRpZһBP`xƳԳ *8N\nN>$ ʸ|j^PD4&ܷη~jRD4&̶ܶ~l^L@0صµ|dN8,Դȴ 4"D$.B^xf\PB.hZN<0"xfXL6$j~l\L<2$ tbRF0$пv\N>&X\PD0 J:ؾȾvhT@2 ~, ,<N^n|¼Լ".@R^rʽ޽rZR@0|jCHC@@ @ @ +eB ;eB CCCCf0C0@@OAA^AdAAAiA@AAAAAAdAdAdA@jA9AýA:AVA00CöA^AAŸA!fB fB+CeBfBeBkfBA@4@@@OAA^AdAAAiA4@AAAAAAdAdAdAAAAAAAdAAAAAlA}A@ @0@AAADA6A7@AAAdAo*C@@AA^AdAAAiA@AAAAAAdAdAdAAAAAAAdAAAAAlA}A*@ @0@AAADA6AAAAAAtAAAbA{AADC P@DD@C @ @ @ `!@@p@*@FBc6B^AdAAAiA@AAAAAAdAdAdA6B7BP"@`"@7FB;FB6BVB@@CBEB_;BABAB7B]:B7B8B8B6B\;B\;BVBDl"@ D0 DC )@ @)@,p)@,p)@ ϘC ϘC C"@ #@@TBA^AdAAAiA"@AAAAAAdAdAdAAAAP#@OBAVBAAAAlA}A@ @0@AAADA6ATBAAAdAUB RBRBVBVBVBVBVBxVBdHB0@UBVBUB`#@(@)@UB)@6XB333333?*??ChCo*C*@@AA^AdAAAiA*@AAAAAAdAdAdAAAAAAAdAAAAAlA}A*@ @0@AAADA6AAAAAAtA+@AbA{AADD+@DDpC 0-@.@+@,@@WBA^AdAAAiA,@AAAAAAdAdAdAAAA-@AAdAAAABlA}A@LBhBBAADA6AiBAAAdA&BCC CC C=C] C0C C.@CBBx CBPDl0/@ D0 DC/@/@@TBA^AdAAAiA/@AAAAAAdAdAdAAAA9TBOBAVBAAAAlA}A@ @0@AAADA6ATBAAAdAUB RBRBVBVBVBVBVBxVBdHB0@UBVBUB@2@0XBVBUBVB6XB333333CC 4@o*C@@AA^AdAAAiA4@AAAAAAdAdAdAAAAAAAdAAAAAlA}A 4@ @0@AAADA6AAAAAAtAAAbA{AADTD`C C"`5@p5@1 6@ 6@C\@CCDialog`CCA T8@ \8@e Af QA A0 Ao AEditMDo*CUA@AA^AdAAAiAAAAAAAAdAdAdAAAAAAAdAAAAAlA}A@ @0@AAADA6AAAAAAtAAAbA{AAHelvMS Sans SerifMS Shell DlgCXCCWinApp@CCAA %B,IfBfBPreviewPagesSettingsFile%dRecent File List`ND~*CNDf0C+C@OAA^AdAAAiAdAAAAAAAdAdAdA+CjA9AýA:AVA00CöA^AAŸA!fB fB+CeBfBeBkfBA ODEB,C@d-CAutomationEmbeddingddeUnregserverUnregisterpptpChCCWinThreadXODN1C0C@OAA^AdAAAiAAAAAAAAdAdAdAA׸A9AýAAVAAA^AAŸAOD1COD1C(CDCCmdTargetHCpCDDC DCFDCC@PDAA A_A0C<3C@CCTempWndXC<2CCCWnd@ChC8 A3 A5 A4 A6 A2 A7 A+ A, AA9!A!{AZAZA- A/7A.7A AA hA8AS*A/A An FA~ A3E0AAfxOldWndProc423AfxWnd42sAfxControlBar42sAfxMDIFrame42sAfxFrameOrView42sAfxOleControl42sGetMonitorInfoAEnumDisplayMonitorsMonitorFromPointMonitorFromRectMonitorFromWindowGetSystemMetricsUSER32DISPLAYcommctrl_DragListMsgxPD3CA@OAA^AdAAAiAAAAAAAAdAdAdAAAAAAAdAAAAAlA}A@ @0@AAADA6AAAAAdAimeAfx:%x:%x:%x:%x:%xAfx:%x:%xPDAAAAInitCommonControlsExCOMCTL32.DLL QDk3CF3C@OAA^AdAAAiAAAAAAAAdAdAdAAAAAAAdAAAAAlA}A@ @0@AAADA6AAAAAdAC 5CCCTempGdiObject(C4CPCCTempDCHCCCRgnhCCCFontCCCBrushCCCPenC4CDCGdiObjectCTPCCPaintDCCPCCWindowDC@CPCCClientDChCR4CDCDCCP DCUserExceptionCP DCResourceExceptionpQDi4C%B@'B 'B'B'B!'BR'B'B'B(B(B()BV)B)B)B:*B*B*+B+Bz;@;@;@;@;@<@3<@c<@GetLayoutGDI32.DLLSetLayoutQDo4C(/B@'B 'B'B'B!'BR'B'B'B(B(B()BV)B)B)B:*B*B*+B+Bz;@;@;@;@;@<@3<@c<@RDu4C/B@'B 'B'B'B!'BR'B'B'B(B(B()BV)B)B)B:*B*B*+B+Bz;@;@;@;@;@<@3<@c<@`RD{4C0B@'B 'B'B'B!'BR'B'B'B(B(B()BV)B)B)B:*B*B*+B+Bz;@;@;@;@;@<@3<@c<@RD4CB;@@SD4C^;@@PSD4C@@SD5C4C@'B 'B'B'B!'BR'B'B'B(B(B()BV)B)B)B:*B*B*+B+Bz;@;@;@;@;@<@3<@c<@SDo5C&5C@xTD3C:@@ABTD4C;@@ABD<@CCStatic(UD5C 8@@OAA^AdAAAiAAAAAAAAdAdAdAAAAAAAdAAAAAlA}A@ @0@AAADA6AAAAAdASCROLLBAR\Software\Dhh%DCSingleDocTemplateUDX9C(3B@SaBA^AdAAAiAAAAAAAAdAdAdA/^BO3BW3Bk3B3B2_B]_B`B9`B`B`B`B3BB5B"aBsoftware%dUDE@=@=@=@/>@y>@>@7@@?@_@DCCFileDialog`VDCXXD@CD9@C DCPreviewView0 D0DC DC `C C (C 8C HC C C,C,,C,cC,C,CCC15CnC ÖCXDn@C|C@TBA^AdAAAiAӃCAAAAAAdAdAdAAAA9TBOBAVBAAAAlA}A@ @0@AAADA6ATBAAAdAUB RBRBVBVBVBVBVBxVB:CUBCVBUBC0XBVBUBVB6XBCӈCϔC@YDo*CC@AA^AdAAAiAAAAAAAAdAdAdAAAAAAAdAAAAAlA}A@ @0@AAADA6AAAAAAtACAbACA DlDCScrollViewH D8 DKBPBcPB .PBMouseZMagellan MSWHEELWheelScrollLinesControl Panel\DesktopMSH_SCROLL_LINES_MSGYDt@C=HB@TBA^AdAAAiAFBAAAAAAdAdAdAAAA9TBOBAVBAAAAlA}A@ @0@AAADA6ATBAAAdAUB RBRBVBVBVBVBVBxVBdHBUBUBVBUB@0XBVBUBVB6XB8 D@CCSplitterWnd`CP D `UB!VB xTB TB55WB55,_WBPP,WBPPWBQQ,WBQQWBd E@%*.*fI64Dx@CCControlBarD@@CCViewD@C@CCFrameWnd`CDNClC0Cu BCb eCv *Cc C!@CB(B(C EB B Be C CBBB3 B#B B B oB#BuBe GBf Bn QB,GC|C,GC|C,GC|C,C,C,C,CEE,CN)CN)C NB B B5E CMSWHEEL_ROLLMSGYD@CB@WBA^AdAAAiABAAAAAAdAdAdAAAABAAdAAAABlA}A@LBhBBAADA6AiBAAAdA&BCC CC C=C] C0C C#BCBBx CB - :%dD|DCStatusBar/DD"lB %mB [mB%lBpmBF$mB mB mB nB +nBHZDKEC@C@OAA^AdAAAiAlBAAAAAAdAdAdAAABACAAdAAAAAlA}A@ @0@kBAdBDA6AB-mBAAdAkBBnBBBB+BmBBB*mBmsctls_statusbar32ZD>nBwnB AnB`CD B1B B1B1=B1BBiB6B̔B 8qBB B~ @B @B @B .pBZDz@CoB@OAA^AdAAAiA-oBAAAAAAdAdAdAAAAAAAdAAAAB3B}A@ @0@AAADA6AAAAAdAjqBB>uBׂBrBuB|vB{wBzxByBBB B2BMBbBB)BzBiB|B4}BBBzB}BDDCToolBar/DD"B %mB YB|B%BF$B GC  B sB B0 B TBDllGetVersionMarlettH[DPKCFC@OAA^AdAAAiAvBAAAAAAdAdAdAAAB^CABdAAAAAlA}A@ @0@kBAdBDA6ABAAAdA9BbBBBBB+BBBBśBToolbarWindow32[DBB A*mB(ADp\KC1DCMiniDockFrameWndDDCDockBar01DD B1)B1ϹB!B/DHD%dzB %mBF$mB Ba aB[DVKC+B@OAA^AdAAAiABAAAAAAdAdAdAAAB^CAAdAAAAAlA}A@ @0@kBAdBDA6ABAAAdABBTBBBBB8_C*mBB+Bh\DKCB@WBA^AdAAAiABAAAAAAdAdAdAAAAsC'CAdAAAABlA}A@LBhBBAADA6AiBAAAdA&BCC CCӸB=C] C0C C#BCBBx CBnB%uDCObjectcombobox DP DCNotSupportedException8 DP DCMemoryExceptionh DDCException\DKCIF@@AB]DKCF@@ABSystem DCCPrintDialog*D D ǕAx]DLC@6C'D8GD(GDGDFDGDFDFDdD2C>Y@@OAA^AdAAAiAAAAA1X@AAdAdAdA]@6c@Rh@h@i@#i@?i@Vi@i@_j@j@Wk@k@Il@k@l@2c@l@l@pm@%n@dn@n@o@To@o@Jp@^@bD@@؟@@@@cDݟ@@؟@'@@@@ @-@@PdD@|@@@dDv@@؟@s@ u@u@cw@XeDJu@@؟@u@v@eDt@t@t@s@ u@u@u@(fDs@]s@ps@s@s@s@s@t@3V@t@cDq@q@q@ r@s@؟@؟@8r@Or@r@r@r@؟@r@ s@cDq@`q@sq@t@ u@q@q@3V@t@pfD|@v@@@@1@?`*D(+DCMemFilefD^CB@B!B5"B"BE@xB.BB BrB-BnB&B&B!BBB6B\BiB{BBBC*DS*-Acommdlg_SetRGBColorcommdlg_helpcommdlg_ColorOKcommdlg_FileNameOKcommdlg_ShareViolationcommdlg_LBSelChangedNotify+DDCPtrListgD^CA@+DDCFileFFHgD^CB@IB!B5"B"BE@xBBBFBrBBBBBBrBBBDllGetClassObject{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}InProcServer32CLSID,DP DCFileException-DP DCArchiveException0-DDCDialogBar/DH-D BgD ^CMB@OAA^AdAAAiABAAAAAAdAdAdAAAB^CAAdAAAAAlA}A@ @0@kBAdBDA6ABAAA/BBBBBBB+B8_CBBx.D@PCCPreviewDCgD&^C&C@CBC'BC5CCCCצCC9C\CCƧCC:CqC+Bz;@;@PCmCxCCϭCC A`C/D dB JBiBc 9Ba [BF$tBn@1B1B!)B a@ uB Bd Bf 1Bf@o A@hD4C@@0DDCMapStringToPtrhDt_CA@ 1Dz_CDCMiniFrameWndD81D +"CC%EC"C1C1C1v C'C$C C (C (C )Cm )Ck I*ChD_CC@WBA^AdAAAiAVCAAAAAAdAdAdAAAAsC'CAdAAAABlA}A@LBhBBAADA6AiBAAAdA&BCC CC C=C] C0C C#BCBBx CBSmall FontsTerminal3DDCPtrArray iD_CA@hiDBBB.INI.HLP84D P DCOleDispatchExceptioniDaCuC@xCB)QΠE>XjD2C;iC@OAA^AdAAAiAAAAAAAAdAdAdAiCiCiCiC jDVjC8jCGjCmjCjCSkCekCRichEdit Text and ObjectsRich Text FormatFileNameWFileNameLink Source DescriptorObject DescriptorLink SourceEmbed SourceEmbedded ObjectObjectLinkOwnerLinkNativejDeAZA`AAAZAAAڛAAAAAڛA6DX@CCToolTipCtrl`C6Dl A A A A8kDscC9A@OAA^AdAAAiAAAAAAAAdAdAdAAAAAAAdAAAAAlA}A@ @0@AAADA6AAAAAdAAtooltips_class32H8D P DCOleExceptionkD dC@@gCBCx8DpLD< kD2CSdC@OAA^AdAAAiAAAAAmCAAdAdAdAYlC]lCilClCmCmC@lD"nCnCnC9nCnCnCh9Dx9DCOleBusyDialog9D`CCOleDialoglDdCEhC@AA^AdAAAiAtAAAAAAAdAdAdAAAAAAAdAAAAAlA}A@ @0@AAADA6AAAAAAlhCAAA(AA%2%5%2\CLSID%1%2\Insertable%2\protocol\StdFileEditing\verb\0&Edit%2\protocol\StdFileEditing\server%3CLSID\%1%5CLSID\%1\ProgID%2CLSID\%1\InprocHandler32ole32.dllCLSID\%1\LocalServer32%3CLSID\%1\Verb\0&Edit,0,2CLSID\%1\Verb\1&Open,0,2CLSID\%1\InsertableCLSID\%1\AuxUserType\2%4CLSID\%1\AuxUserType\3%6CLSID\%1\DefaultIcon%3,%7CLSID\%1\MiscStatus32CLSID\%1\InProcServer32%3CLSID\%1\DocObject0%2\DocObject0CLSID\%1\PrintableCLSID\%1\DefaultExtension%9, %8p:D:D:D:DD;D`;D|;D;D;D;Dp:D:D:D:DD;D|;D;D;D;Dp:D:D:D:DD;D`;D|;D;D;D;D*A.AAA_yn_y1_y0frexpfmod_hypot_cabsldexpmodffabsfloorceiltancossinsqrtatan2atanacosasintanhcoshsinhlog10logpowexpSunMonTueWedThuFriSatJanFebMarAprMayJunJulAugSepOctNovDecTZGetLastActivePopupGetActiveWindowMessageBoxAuser32.dll1#QNAN1#INF1#IND1#SNANOAOAOAOAFFFFt0 PA+ LOOP j:#`Lj:#`Lj:#`L"\Dw="\Dw=:s *Dw=:s *Dw=|:s *Dw=:s *Dw=lRۈH<44FF4F4Ft0 QbH6 F#N-+.7PBF444:KQFBшH<H<jH<G(H<G(H<G(H<G(H<G(H<G(H<G(H<G(H<G(H<G(H<G(H< G(H< G(H< G(H< G(H< G(H<G(H<G(H<G(H<G(H<G(H<G(H<G(H<G(H<G(H<G(H<G(H<G(H<G(H<K0H<K0H<K0H<K0H<K0H<K0H<K0H<K0H<0:s *Dw=4 F F F'FFFFFButtonPzAmAListBox AmAEditAmAComboBoxPAnAStatic APoA0ComboLBox A@nADDDDMDMDMDpMDMDDMD@D`D(NDND@ND`DPNDDDNDxNDMDpMDNDDNDDNDpMDODDODxNDMDpMD8ODDHODDpODNDODDODDODNDODDOD(DPD(PD(D0PDMDMDpMDXPDDhPDHDPDPDPDHDPDDPDMDMDpMDPDDQDD8QDpMDPQDD`QDDQD8QDpMDQDDQDDQD8QDpMDQDDRDD(RD8QDpMD@RDDPRDD DRDxRDpMDRD DRD8DRDxRDpMDRD8DSDxRDpMD0SDD@SDPDhSD8QDpMDSDPDSDhDSDxRDpMDSDhDSDDD8D8TD TDTDpMDPTD8DhTD`DTD TDTDpMDTD`DTDDTDMDMDpMDUDDUDDDXUD@UDMDpMDpUDDUDDUDNDUDDUDD8DVDVDMDMDMDpMD0VD8DPVDXDpDVDxVDpMDVDpDVDDVDTDpMDVDDWDD0WDNDHWDDXWDDWDNDWDDWDDWDNDWDDWDD XDWDND8XDDHXD@DXDxDXDXDpXDMDMDpMDXDxDXDDYDMDMDMDpMDYDD0YDXDpXDMDMDpMDXYDXDpYDDYDMDMDpMDYDDYDDDZDYDMDMDpMD ZDD8ZDD`ZDPDxZDDZD0DZDMDMDpMDZD0DZDXD[DYDMDMDpMD [DXD8[DpD`[DPDx[DpD[DD[DYDMDMDpMD[DD[DDD \D\DYDMDMDpMD8\DDX\D0D\D TDTDpMD\D0D\DPD\D TDTDpMD\DPD]DxD0]DVDMDMDMDpMDH]DxDh]DD]DND]DD]DD]D]DD^DD(^D@^DDH^DDp^DpMD^DD^DD^DpMD^DD^D0D_D^DpMD(_D0D8_DHD`_DpMDx_DHD_DhD_DMDMDMDpMD_DhD_DDDDDP`D8`D `D`D`Dh`DD`D(D`DMDpMD`D(D`DPDhDDD@aD(aDaD`DXaDDpaDDaDxRDpMDaDDaDDDbDaDMDpMDbDD0bD8DXDpbDXbD`DbDXDbDDDbDbD`D`DbDDcDDDHcD0cD`D`cDDpcD(DHDcDcD`DcDHDcDxDDdDdD`D0dDD@dDDhdDpeD`DdDDdDDdDMDpMDdDDdDD@D eDeD`D8eD@DHeDxDDeDpeD`DeDDeDDDeDeD`DfDDfDD@fDXfDD`fDhDfDxVDpMDfDhDfDDfDpMDfDDgDxVDpMD(gDXD8gDD`gDYDMDMDpMDxgDDgDDgD8QDpMDgDDgDDhDxRDpMD hDD0hDDXhDpMDphDDhD\DYDMDMDpMDhDDhD0DhDpMDiD0DiDHD8iDPiDHDXiDDiDTDpMDiDDiDD DiDiD`DjD DjDaDMDpMD8jDDHjDHDhDDjDjDpjD`DjDDjDDjDMDMDpMDkDD(kDDPkDTDpMDhkDDxkDDkDMDpMDkDDkDD DlDkD`D lD D0lDPDpDplDXlDVDMDMDMDpMDlDpDlDDlDNDlDDlDD mD8mDD@mD mD@CMCXCcCnCyCCCCCC C ̳C׳C CCCCC @nD0C8CCC xnD`ChCsCCCCCCCCŴC ʹC شCC CC oDC @oD8C0C poD`CkCvCC oDC oDC pDC (pDC PpD C xpD@C pD`C pDC pDC qDC @qDCCCC CC"C-C qDPC qDpC qDCCCC 0rDзC XrDCCC rD C(C6C rDPC rDpCxC  sDC HsDCCøC sDC sDC sDC sDtD(C0C0tD DA `tDptDtD DmA tDPC[CcC tDxC uDC @uDC huDC uD̹CԹC߹CC uDC uDC  vD(C HvD2(pl~ʹع,Hb|к޺$2BRpZһBP`xƳԳ *8N\nN>$ ʸ|j^PD4&ܷη~jRD4&̶ܶ~l^L@0صµ|dN8,Դȴ 4"D$.B^xf\PB.hZN<0"xfXL6$j~l\L<2$ tbRF0$пv\N>&X\PD0 J:ؾȾvhT@2 ~, ,<N^n|¼Լ".@R^rʽ޽rZR@0|jPtImageRW.dllPtPDF417Decode.dllPtQRDecode.dllPtDMDecode.dllFreeLibraryLoadLibraryA}GetWindowsDirectoryALoadResourceFindResourceALockResourceGlobalFreeGlobalUnlockGlobalLocklstrcmpAGetCurrentThreadIdGetCurrentThreadlstrcmpiAGlobalDeleteAtomGlobalAlloc$GetModuleFileNameACloseHandle>GetProcAddress&GetModuleHandleAlstrcpyAGlobalFindAtomAGlobalAddAtomAGlobalGetAtomNameAlstrcatAtGetVersionqSetLastErrorMulDivInterlockedIncrementInterlockedDecrementlstrlenAWideCharToMultiByteMultiByteToWideChar4GetPrivateProfileIntA:GetPrivateProfileStringAWritePrivateProfileStringAlstrcpynA GetFileAttributesAcGetTempFileNameAGetFullPathNameAlSetFileTimeGetFileTimeGetDiskFreeSpaceAGetLastErrorLocalFreeFormatMessageAGlobalFlagsSizeofResourceLocalAllocInitializeCriticalSectionTlsAllocUDeleteCriticalSectionGlobalHandleTlsFreeLeaveCriticalSectionGlobalReAllocfEnterCriticalSectionTlsSetValueLocalReAllocTlsGetValueGetCurrentDirectoryAEGetProcessVersionGetCPInfo1GetOEMCPhGetThreadLocalecDuplicateHandleGetCurrentProcess4CreateFileAReadFileWriteFilejSetFilePointerFlushFileBuffersLockFileUnlockFileaSetEndOfFileMoveFileAWDeleteFileAFindCloseFindFirstFileAwGetVolumeInformationATGetStringTypeExANGetShortPathNameAGetFileSizeLocalFileTimeToFileTimeSystemTimeToFileTimedSetErrorModeFileTimeToSystemTimeFileTimeToLocalFileTimemGetTickCount/RtlUnwindPGetStartupInfoAGetCommandLineA}ExitProcessTerminateProcessHeapFreeHeapAlloc RaiseExceptionHeapReAllocHeapSizeGetACPpGetTimeZoneInformationSGetStringTypeAVGetStringTypeWUnhandledExceptionFilterFreeEnvironmentStringsAFreeEnvironmentStringsWGetEnvironmentStringsGetEnvironmentStringsWmSetHandleCountRGetStdHandleGetFileType GetEnvironmentVariableAuGetVersionExAHeapDestroyHeapCreateVirtualFreeVirtualAllocIsBadWritePtrSetUnhandledExceptionFilterLCMapStringALCMapStringWIsBadReadPtrIsBadCodePtr|SetStdHandle!CompareStringA"CompareStringWbSetEnvironmentVariableAKERNEL32.dllUpdateWindowEnableWindow\GetWindowRectzInvalidateRectGetClientRectSendMessageAMessageBeep&SetCursorBCopyIconLoadCursorAIsWindowEnabledGetDlgItemVGetWindowLongA5GetParentDestroyWindowLCreateDialogIndirectParamAFGetSystemMetricsIsWindowSetActiveWindowGetActiveWindowEndDialog3GetNextDlgTabItemPostQuitMessagePostMessageAgShowOwnedPopupsMessageBoxAGetLastActivePopupbSetWindowsHookExAGetCursorPosPeekMessageAIsWindowVisibleValidateRectCallNextHookExGetKeyStateDispatchMessageATranslateMessage*GetMessageAGetFocusEnableMenuItem4CheckMenuItem9SetMenuItemBitmapsModifyMenuA'GetMenuStateLoadBitmapAGetMenuCheckMarkDimensions[GetWindowPlacementIsIconicqSystemParametersInfoAyIntersectRectOffsetRectRegisterWindowMessageA[SetWindowPosXSetWindowLongARGetWindow0SetForegroundWindowGetForegroundWindow,GetMessagePos-GetMessageTimeDefWindowProcARemovePropACallWindowProcA:GetPropAUnhookWindowsHookExBSetPropAGetClassLongAYCreateWindowExAGetDlgCtrlID^GetWindowTextA_GetWindowTextLengthA#GetMenuItemIDBGetSubMenu"GetMenuItemCountGetMenuRegisterClassAGetClassInfoAwsprintfAWinHelpAGetCaptureIsChildLGetTopWindowGSetScrollPos?GetScrollPosHSetScrollRange@GetScrollRangehShowScrollBarFSetScrollInfo>GetScrollInfo ScrollWindowEndDeferWindowPosDCopyRect BeginDeferWindowPosDeferWindowPosEqualRect ScreenToClientAdjustWindowRectEx/SetFocusCGetSysColorMapWindowPointsSendDlgItemMessageALoadIconA,SetDlgItemTextAIsDialogMessageA^SetWindowTextAMoveWindowjShowWindow:ClientToScreenGetDCReleaseDCTGetWindowDC BeginPaintEndPaintsTabbedTextOutADrawTextAdGrayStringAWSetWindowContextHelpIdMapDialogRectDestroyCursorDSetRectFillRectPtInRectFindWindowAIsRectEmptyESetRectEmptyLoadAcceleratorsATranslateAcceleratorAReleaseCaptureGetDesktopWindowDestroyMenuLoadMenuA5SetMenu ReuseDDElParamUnpackDDElParamBringWindowToTopIsZoomedqInflateRectRedrawWindowSetCapture(SetCursorPos>SetParentAppendMenuADeleteMenuEGetSystemMenuwvsprintfALoadStringAGetClassNameAtInsertMenuA(GetMenuStringADGetSysColorBrushDestroyIcon%CharNextA@CopyAcceleratorTableA2GetNextDlgGroupItem/CharUpperAGGetTabbedTextExtentARSetTimerKillTimerWindowFromPoint|InvertRectGetDCExLockWindowUpdateRegisterClipboardFormatAPostThreadMessageAUSER32.dllRectangleuGetTextMetricsA_GetStockObject7CreateFontIndirectAOGetObjectA$CreateBitmapGetClipBoxSetTextColorSetBkColorPDeleteDCStartDocASaveDCRestoreDCSelectObjectSetBkModeSetPolyFillModeSetROP2SetStretchBltModeSetMapModeSetViewportOrgExOffsetViewportOrgExSetViewportExtExScaleViewportExtExSetWindowOrgExSetWindowExtExScaleWindowExtExSelectClipRgnExcludeClipRectIntersectClipRectMoveToExLineToSetTextAlignGetCurrentPositionExSDeleteObjectHCreateRectRgn%GetDeviceCapsxGetViewportExtEx{GetWindowExtExDCreatePenMCreateSolidBrush=CreateHatchBrushCCreatePatternBrushPtVisibleRectVisibleTextOutAExtTextOutAEscapePatBltNDPtoLPyGetViewportOrgExAbortDocZEndDoc\EndPageStartPageSetAbortProc+CreateDCALPtoDPnGetTextExtentPoint32AStretchDIBits*CreateCompatibleDC)CreateCompatibleBitmapGetCharWidthA6CreateFontAiGetTextColorGetBkColorMGetNearestColor`GetStretchBltModeXGetPolyFillModeeGetTextAlignGetBkModeYGetROP2sGetTextFaceA|GetWindowOrgExGGetMapModeSetRectRgnCombineRgnICreateRectRgnIndirectBitBltGDI32.dllCommDlgExtendedError GetSaveFileNameA GetOpenFileNameAPrintDlgAGetFileTitleAcomdlg32.dllClosePrinterGDocumentPropertiesA|OpenPrinterAWINSPOOL.DRVzRegQueryValueA[RegCloseKeyfRegEnumKeyAqRegOpenKeyAbRegDeleteKeyA_RegCreateKeyExArRegOpenKeyExA{RegQueryValueExARegSetValueExAdRegDeleteValueASetFileSecurityAGetFileSecurityA^RegCreateKeyARegSetValueAADVAPI32.dllrShellExecuteADragFinishDragQueryFileAExtractIconAHSHGetFileInfoASHELL32.dllCOMCTL32.dlloledlg.dllCLSIDFromProgIDCLSIDFromStringCoGetClassObject StgOpenStorageOnILockBytesStgCreateDocfileOnILockBytes`CreateILockBytesOnHGlobalOCoTaskMemFreeNCoTaskMemAllocOleInitializeOleUninitializeCoFreeUnusedLibraries@CoRegisterMessageFilterGCoRevokeClassObjectOleFlushClipboardOleIsCurrentClipboardole32.dllOLEPRO32.DLLOLEAUT32.dllKGetProfileStringAIsWindowUnicode~DefDlgProcADrawFocusRectExcludeUpdateRgneShowCaretfHideCaretUnregisterClassApGetTextExtentPointA0CreateDIBitmapq3Cu5C5CAAADA]=C^?CUCl0CTCTCdC A`@eA{AAA5A3C 4C<@BBKCKCSCUCwC@CaC@@5AAr6AAlDDDDDDDDDDxDdDTDHDD.?AVCObject@@>D.?AVCCmdTarget@@>D.?AVCWnd@@>D.?AVCDialog@@>D.PAVCException@@>D.?AVCNoTrackObject@@>D.?AV_AFX_WIN_STATE@@>D.?AVCWinThread@@>D.?AVCWinApp@@>D.?AVCCommandLineInfo@@>D.?AV_AFX_CTL3D_STATE@@>D.?AV_AFX_CTL3D_THREAD@@>D.?AVCCmdUI@@A>D.?AVCTestCmdUI@@>D.PAVCUserException@@>D.?AVCTempWnd@@>D.?AVCDC@@>D.?AVCClientDC@@>D.?AVCWindowDC@@>D.?AVCPaintDC@@>D.?AVCGdiObject@@>D.?AVCPen@@>D.?AVCBrush@@>D.?AVCTempDC@@>D.?AVCTempGdiObject@@>D.PAX>D.PAVCObject@@>D.PAVCSimpleException@@>D.PAVCResourceException@@>D.?AVCException@@>D.?AVCSimpleException@@>D.?AVCResourceException@@>D.?AVCUserException@@>D.?AVCStatic@@DD>D.?AVCDocTemplate@@>D.?AVCSingleDocTemplate@@>D.?AVCOccManager@@>D.?AVCCommonDialog@@>D.?AVCFileDialog@@>D.?AVCFile@@>D.?AVCMirrorFile@@>D.?AVCFileException@@>D.?AV_AFX_THREAD_STATE@@>D.?AVAFX_MODULE_STATE@@>D.?AVAFX_MODULE_THREAD_STATE@@>D.?AV_AFX_BASE_MODULE_STATE@@>D.?AVCView@@>D.?AVCScrollView@@>D.?AVCPreviewView@@>D.?AVCPrintingDialog@@>D.?AVCFrameWnd@@>D.?AVCControlBar@@>D.?AVCStatusBar@@>D.?AVCStatusCmdUI@@>D.?AVCSplitterWnd@@>D.?AVCToolBar@@>D.?AVCToolCmdUI@@>D.?AVCDockBar@@>D.?AVCMiniFrameWnd@@>D.?AVCMiniDockFrameWnd@@>D.PAVCMemoryException@@>D.PAVCNotSupportedException@@>D.?AVCMemoryException@@>D.?AVCNotSupportedException@@>D.?AVCPrintDialog@@>D.?AUCThreadData@@>D.?AVCRecentFileList@@>D.?AVCHandleMap@@>D.?AVCMapPtrToPtr@@>D.?AVCMenu@@>D.?AVCTempMenu@@>D.?AVCDocManager@@>D.?AVCNewTypeDlg@@>D.?AUIOleWindow@@>D.?AUIOleInPlaceUIWindow@@>D.?AUIOleInPlaceFrame@@>D.?AVXOleIPFrame@COleControlContainer@@>D.?AVCOleControlContainer@@>D.?AUIUnknown@@>D.?AUIParseDisplayName@@>D.?AUIOleContainer@@>D.?AVXOleContainer@COleControlContainer@@>D.?AVCFont@@>D.?AVCEnumArray@@>D.?AVCEnumUnknown@@>D.?AUIRowsetNotify@@>D.?AVXRowsetNotify@COleControlSite@@>D.?AUIOleInPlaceSite@@>D.?AVXOleIPSite@COleControlSite@@>D.?AUINotifyDBEvents@@>D.?AVXNotifyDBEvents@COleControlSite@@>D.?AUIOleClientSite@@>D.?AVXOleClientSite@COleControlSite@@>D.?AUIBoundObjectSite@@>D.?AVXBoundObjectSite@COleControlSite@@>D.?AVXEventSink@COleControlSite@@>D.?AVCOleControlSite@@>D.?AUIPropertyNotifySink@@>D.?AVXPropertyNotifySink@COleControlSite@@>D.?AUIDispatch@@>D.?AVXAmbientProps@COleControlSite@@>D.?AUIOleControlSite@@>D.?AVXOleControlSite@COleControlSite@@>D.?AVCDataSourceControl@@:s *Dw=:s *Dw=:s *Dw=>D.?AVCMemFile@@>D.?AVCPtrList@@>D.PAVCFileException@@>D.?AVCDialogBar@@>D.?AVCPreviewDC@@>D.?AVCRgn@@>D.?AVCMapStringToPtr@@>D.?AVCPtrArray@@>D.?AVCDockContext@@>D.PAVCOleException@@>D.?AVCOleDispatchException@@>D.PAVCOleDispatchException@@;Zx0Nm>D.?AUIEnumVOID@@>D.?AVXEnumVOID@CEnumArray@@>D.?AUISequentialStream@@>D.?AUIStream@@>D.?AVCArchiveStream@@>D.?AVCToolTipCtrl@@>D.?AVCOleException@@>D.?AVCOleMessageFilter@@>D.?AUIMessageFilter@@>D.?AVXMessageFilter@COleMessageFilter@@>D.?AVCOleDialog@@>D.?AVCOleBusyDialog@@>D.?AV_AFX_OLE_STATE@@ us@ŷ@ŷ@/@>D.?AVtype_info@@A`y!@~ڣ @ڣ AϢ[@~QQ^ _j21~        ! 5A CPR S WY l m pr   )    ??D(@D$@D @D@D@D@D@D@D@D?D?D?D?D?D?D?D?D?D?D?D?D?D?D?D?D?D?D?D?Dx?D?Dp?Dh?D`?DT?DL?D@?D4?D0?D,?D$?D?D?D?A*@2A2A2A2A2A2AHAD8ADrDrD ((((( H  x CDCD CD |CDPCD CDBDBDBDpBD8BDBDADxADyADzADADAD`E>E&.EP>EP>EP>EP>EP>EP>EP>EP>EP>EE@@@@ @P@$@@ @4@N@ p+ŝi@]%O@qוC)@D@<զIx@oGAkU'9p|Bݎ~QCv)/&D(DJzEeǑF e uuvHMXB䧓9;5SM]=];Z] T7aZ%]g']݀nLɛ R`%u?q= ףp= ף?Zd;On?,eX?#GGŧ?@il7?3=BzՔ?aw̫?/L[Mľ?S;uD?g9Eϔ?$#⼺;1az?aUY~S|_?/D?$?9'*?}d|FU>c{#Tw=:zc%C1xo8r*(Z0p>И2P`(0pPFȣ*J$0ȯPd`,`}h"p"Po"xz"}<( @wwwwwwwwwwwwwp    """"""""""        """"""""""    "/""/""/""       ""/""""/        """"""""""        wwwwwwwwwwwx(   """"    ""    """"  (Ȁ PtBarcodeDec Times New RomanPj2OKP!, Home Page:PR!U http://www.PartiTek.comP2? Order Full SDK:PR2} http://www.PartiTek.com/order.htmPC7Support Email:PRCU support@PartiTek.comPT, Sales Email:PRTU sales@PartiTek.comPP, WPtBarcodeDecȀSetting Times New RomanP> Px P>" Px" Pt<> P S- OKPHS- CancelPS- DefaultP# Start XP## End XP^ Start YP^$ End YP ,Seach AreaPd-It can improve recognition performance to set suitable search area, which is used to exclude figures around the barcode. It can speed up to set the max searched symbols. For more detail, please refer to the SDK manual.P?Y Max Searched Symbols( @?( wppwp`wwww`pwwwww? (ȀaAbout DemoMS Sans SerifP P+wDemo Version 2.0P+(wCopyright (C) 2004P2OKP+<wwww.PartiTek.com&File&Open... Ctrl+ORecent FileAE&xit&Decode&PDF417&QR Code&Data Matrix&Setting&ViewZoom &InZoom &Out&Toolbar&Status Bar&Help@&About Demo... C" N O P V%+.#uPuQ -"-% X#Z+<4VS_VERSION_INFO?StringFileInfox040904b0Comments CompanyNameRFileDescriptionDemo MFC Application6 FileVersion2, 0, 0, 0*InternalNameDemoJLegalCopyrightCopyright (C) 2004(LegalTrademarks: OriginalFilenameDemo.EXE PrivateBuildBProductNameDemo Application: ProductVersion2, 0, 0, 0 SpecialBuildDVarFileInfo$Translation @(xwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwtGwwwwwwwwwwtGwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwDGwwwwwwwwwwDGwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwtDwwwwwwwwwwtDwwwwwwwwpwwwwwwwpwwwwwwpwwwwppwwwwwwwDDwDGwwwwwwwDDwDGwwwwwwww wwwwwwp3333wwwwwwwwwwDDDwwwwwwwDDDwwwwwwwww wwwwwwp33330wwwwwww{wwwwwtGwwwwwwtGwwwwwwwwwpwwwwwwwp3333wwwwwwxwwwwwtOGwwwwwwtGwwwwwwwww wwwwwwwp33330wwwwpwwwwOOwwwwwwOwwwwwwwww wwwwwwwpwwwwwwwwpppwwwwODDOwwwwwwODDOwwwwwwwww wwwwwwwpwwwwwwpwwwwODDOwwwwwwODDOwwwwwwwww wwwwwwpwwwwwwwppwwwwOOwwwwwwOwwwwwwwwpwwwwwwpwwwwwwwpwwwwtOGwwwwwwtGwwwwwwwp wwwwwwwwwpwwwwwpwwwwwtGwwwwwwtGwwwwwwwppwwwwwwwwwwwwwwwwwwwwwwwwDDwwwwwwwwDDwwwwwwwwp wwwwwwwwwpwppwwwwwwwwwwwwtDDGwwwwwwwwtDDGwwwwwwwww wwwwwwwwwwwwwwwwwwpwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwpwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww( @80p`????? p( HxHd)9|x0!? @4 (F'|Kpxzpxzz`zzz܀zzzz zzxxxzpzzz zzxxxzpzzz zzxxxzzzzzzÈpxzpxzz:wwwwwwwwwwwwwwwwwwswwwwwwwwwwtwwwwwXwww wwAzzzzzwwwzzzzzwwwhzzzzzwwwzz zzzwwxԊ{x{wxxxwxxwxxxxxxzzzzzwwwwwwwwwwqzzzzzzzzzzzz zzzwzzzzzwwKzz zzzwwxzzzzzwzz zzzwwzzzzzwwzz zzzxwpzzzzzhzzzzzwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwȀ FNewMS Shell DlgP{&New P}1dP(OKP(CancelP+(F&Help( Pwww(' (! wwwwwwwxwwwxwwwwxwwwwwww ( @  ?????( `  @@@@  `q @4 _MS Shell DlgP PrintingPPon theP'P1P;P.J(CancelD@JMS Shell DlgP, &Print...P0, &Next PageP^, Pre&v PageP, P, Zoom &InP, Zoom &OutP, &Close"!=Demo Demo Bmp Files (*.bmp) .bmp Demo.Document Demo DocumentDemoReadyEXTCAPNUMSCRLOVRRECCreate a new document NewOpen an existing document OpenClose the active document CloseSave the active document Save0Save the active document with a new name Save As&Change the printing options Page Setup3Change the printer and printing options Print SetupPrint the active document Print Display full pages Print Preview?Display program information, version number and copyright About4Quit the application; prompts to save documents ExitOpen this documentOpen this documentOpen this documentOpen this documentOpen this documentOpen this documentOpen this documentOpen this documentOpen this documentOpen this documentOpen this documentOpen this documentOpen this documentOpen this documentOpen this documentOpen this document(Switch to the next window pane Next Pane5Switch back to the previous window pane Previous Pane(Split the active window into panes SplitErase the selection EraseErase everything Erase All3Copy the selection and put it on the Clipboard Copy1Cut the selection and put it on the Clipboard CutFind the specified text FindInsert Clipboard contents PasteRepeat the last action Repeat1Replace specific text with different text Replace%Select the entire document Select AllUndo the last action Undo&Redo the previously undone action Redo'Show or hide the toolbar Toggle ToolBar,Show or hide the status bar Toggle StatusBarChange the window sizeChange the window positionReduce the window to an iconEnlarge the window to full size"Switch to the next document window&Switch to the previous document window9Close the active window and prompts to save the documents!Restore the window to normal sizeActivate Task ListOpenSave AsAll Files (*.*)Untitled'Close print preview mode Cancel Previewan unnamed fileDecode PDF417 DecodeZoom in Zoom inZoom out Zoom outSet Search Area&HideNo error message is available.'An unsupported operation was attempted.$A required resource was unavailable.Out of memory.An unknown error has occurred.Invalid filename.Failed to open document.Failed to save document.Save changes to %1? Failed to create empty document.The file is too large to open.Could not start print job.Failed to launch help.Internal application error.Command failed.)Insufficient memory to perform operation.PSystem registry entries have been removed and the INI file (if any) was deleted.BNot all of the system registry entries (or INI file) were removed.FThis program requires the file %s, which was not found on this system.tThis program is linked to the missing export %s in the file %s. This machine may have an incompatible version of %s.#Unable to read write-only property.#Unable to write read-only property.Unexpected file format.V%1 Cannot find this file. Please verify that the correct path and file name are given.Destination disk drive is full.5Unable to read from %1, it is opened by someone else.AUnable to write to %1, it is read-only or opened by someone else..An unexpected error occurred while reading %1..An unexpected error occurred while writing %1.Please enter an integer.Please enter a number.*Please enter an integer between %1 and %2.(Please enter a number between %1 and %2.(Please enter no more than %1 characters.Please select a button.*Please enter an integer between 0 and 255. Please enter a positive integer. Please enter a date and/or time.Please enter a currency.No error occurred.-An unknown error occurred while accessing %1.%1 was not found.%1 contains an invalid path.=%1 could not be opened because there are too many open files.Access to %1 was denied..An invalid file handle was associated with %1.<%1 could not be removed because it is the current directory.6%1 could not be created because the directory is full.Seek failed on %15A hardware I/O error was reported while accessing %1.0A sharing violation occurred while accessing %1.0A locking violation occurred while accessing %1.Disk full while accessing %1..An attempt was made to access %1 past its end.No error occurred.-An unknown error occurred while accessing %1./An attempt was made to write to the reading %1..An attempt was made to access %1 past its end.0An attempt was made to read from the writing %1.%1 has a bad format."%1 contained an unexpected object. %1 contains an incorrect schema.#Unable to load mail system support.Mail system DLL is invalid.!Send Mail failed to send message.pixelson %1 &One Page &Two PagePage %uPage %u Pages %u-%u prn Output.prn1Printer Files (*.prn)|*.prn|All Files (*.*)|*.*|| Print to Fileto %1yara-4.5.3/tests/data/e3d45a2865818756068757d7e319258fef40dad54532ee4355b86bc129f27345000066400000000000000000000150001501365277300246640ustar00rootroot00000000000000MZ@ !L!This program cannot be run in DOS mode. $%vvvvvٛVvvٛGvv8vvٛPvvvvٛ@vvٛQvvٛRvvRichvPELQ0mM!  `p88\HUPX0`UPX1 p@UPX2@3.03UPX! f4ٍf8kf>&(|UhF 0< }@j]/}P`|!^ QnRlmX_ EPv_EMQu.xv%QURP  v57 9U}t$vo$1>R}:u`/ tD؋EM PEy 6QEv" /tL @ $/9E 2%4 )y D @8rLLP+dJ^ CrKt8Dr*C2r2YGɕQC CCZYFo 2½.bb#E%MXjR2J&{tS2F O'#!(9=OɠN O*-$#\ 3L$CD,#%r_T3@}FN;L Z9:Ds;tu.2D;tNmV_;ghd b'u$d WP!6+Ww/RhSjuCO{4!ht.,%5p|PQd\ek/k߶*!Ö4;$&!#Tc 5Y]82YRFjD`qؤ0DYgj7nY'/nAwY4ॹP}yKPP6l, ,/oܟ=lYNoYH]u(-4WJ;sMJaoT;r*%00H!/PTX\`_qXʸMZf9pnlA<8PEu 3ҹ H‹¡:f?H1Anq3WD%vK}F ;rX;r BB{(;rjNkpOj ΀fP pF1z3Ŋd àDikh( U-%^P<^:"@$)hiduYXvƱ=`/1ddmdhlJ.ct0V (ݾ2tlmKl+՜<` ÕlQh]i!hQ!bz4v hGSWN@ nf ?5kiF`V bmu se 'V::$D3;uOoY  [^_:22vx|H;Nry@3Á(Gy܉؉ԉ5Љ=Wf K4%-c 87Vl#0c=$ ? >w7ܶ2 x,Y^(j=to"Yj\[~ =G(#h 0[ b3<40,($  Q UG 0.1>bindre _cont[extsolveKun/new)/troylis6r/xt_e n#_IDL:omg.org/CosNamP oCR otFo|d:1C3CannK6Pbcee8@}!t'0@ 7N09li}'̄)s /Wa nobjectm~miss_d4o 2Unkwn Enum Valu- v = %uo (%s)CSeq leTth of `0_Of_f0+l`0/{,nGx:ptiۿl GIOP MLsag"CF+h_m^`lYyCbl_SOpera#_ReturK%iVWU +NwComp$t}.idu)tskBc%;Beb"WCOSNAMING , KIt(or aHS-cg) D%>5 U-)APIl{#1 B/zDY$`(_IsDebuggerPo*WSetUnhandleêdFilܷ+G6CurrB}ssT.Y[a$SysmTimeAs;e =I=dThad~1ckCouQubyPfoiQ/Z7ab\7Libra'CallWI!ldkĪs6e2aXZ"3fg_f3e"k4gcol_soݷntpto_t(_d_i} s subt3ջI5CDR9nlk'boRnlBwuViowMvM.u^[ rg@8:@8 @"!xxAA -==-==00$$Std00Ptd $$QtdRtd-==   GNUGNUU'`{d%+EV=z k|P "l hrx, F"c aU __gmon_start___ITM_deregisterTMCloneTable_ITM_registerTMCloneTable__cxa_finalizeprotected_funmainfoofoo64FOO64a_valueFOOstrstuffstuffstrmemstuffstuffmemSTRALLCAPSALLCAPSSTRlong_function_to_make_the_tlsh_hash_workzweak_funlibdyn.solibc.so.6GLIBC_2.2.5ui ==ph@h@?????@@@@ @(@0@ 8@ @@ H@ P@ X@`@HH/HtH5/%/@%/h%/h%/h%/h%/h%/h%/h%/hp%/h`%/h P%z/h @%r/h 0%j/h H=i/Hb/H9tH.Ht H=9/H52/H)HH?HHHtH}.HtfD=.u3UH=Z.Ht H=.H.c.]f.ff.@gUH]UHH-m. +]HH;$ @hzRx $FJ w?;*3$"DYAC B d@aAC \ p  4==o (  ?8@ o`oo2o=6FVfvh@GCC: (GNU) 12.2.0<4<#< 4g-B4U%U%c. -- ?LLu=/ 4K^. 44 'K <+K../sysdeps/x86_64/crti.S/build/glibc/src/glibc/csuGNU AS 2.39.0../sysdeps/x86_64/crtn.S/build/glibc/src/glibc/csu../sysdeps/x86_64crti.Scrtn.S4<   0! p7p@C=j v=  4h@= p@?  &("15; JNW a\gpv  "crtstuff.cderegister_tm_clones__do_global_dtors_auxcompleted.0__do_global_dtors_aux_fini_array_entryframe_dummy__frame_dummy_init_array_entrytoto.c__FRAME_END___fini__dso_handle_DYNAMIC__GNU_EH_FRAME_HDR__TMC_END___GLOBAL_OFFSET_TABLE__init_ITM_deregisterTMCloneTablememstuffzweak_funFOOfoo64__gmon_start__foostrstuffmainALLCAPSSTRstuffmemFOO64long_function_to_make_the_tlsh_hash_workSTRALLCAPSa_value_ITM_registerTMCloneTableprotected_fun__cxa_finalize@GLIBC_2.2.5stuffstr.symtab.strtab.shstrtab.note.gnu.property.note.gnu.build-id.gnu.hash.dynsym.dynstr.gnu.version.gnu.version_r.rela.dyn.rela.plt.init.text.fini.eh_frame_hdr.eh_frame.init_array.fini_array.dynamic.got.got.plt.data.bss.comment.debug_aranges.debug_info.debug_abbrev.debug_line.debug_str.debug_line_str.debug_rnglists0.$Ao(K ((S  [o22*ho`` wB@@8  144  $( ( =-=-=-?/(?/h@h0p@p00p001FV1$!z1-0C2[802;H2B 3  68Xyara-4.5.3/tests/data/foo.yar000066400000000000000000000000671501365277300160460ustar00rootroot00000000000000include "include/bar.yar" rule foo { condition: bar } yara-4.5.3/tests/data/include/000077500000000000000000000000001501365277300161665ustar00rootroot00000000000000yara-4.5.3/tests/data/include/bar.yar000066400000000000000000000000621501365277300174450ustar00rootroot00000000000000include "../baz.yar" rule bar { condition: baz } yara-4.5.3/tests/data/mtxex.dll000077500000000000000000000230001501365277300164030ustar00rootroot00000000000000MZ@ !L!This program cannot be run in DOS mode. $_'K>IK>IK>I.XJI>I.XMA>IK>HW>I.XHN>I.XIJ>I.XAI>I.XJ>I.XKJ>IRichK>IPEd3l"   p`A&&<P@`p"T !.textP  `.rdata @@.data0@.pdata@@@.rsrcP @@.reloc`$@BH(uaH(H\$Ht$WH H=Y%IHHuK3H AHHuH# N\3H %tH%Hu.H $HHHt3H $H$LHH H\$0Ht$8H _H(H$H$HuH 3H(H\$Hl$Ht$ATAVAWH 3MLvDeH%0HpH;t3H5$uA$tH-#HtdH5#LLHH;r7HHtHH #H#L;uL;tLHLHHH{#H|##EHn#eH%0HpH;t3H54#u-#t _H5V #L%UI;s#uH9t HHI;rt3gH H "u HH"H9"t(H "tH"MƺIH\$@Hl$HHt$PH A_A^A\H\$Ht$WH IHuLNjHH\$0Ht$8H _HHX L@PHHVWAVHPLމ\$ ;wu9u 3ۉ\$ B;L !MtB;DƉL$I ؉D$ 3ۉ\$ s$xL$pyL$I؉D$ 3ۉ\$ s$xL$p?L$II؉D$ 3ۉ\$ s$xL$p;E33I $xL$p\$ E33I$xL$p\$ H Ht(E33I $xL$p\$ turL$I؉D$ 3ۉ\$ s$xL$pH% Ht4=et+L$I ؉D$ 3ۉ\$ s$x;w H$HPA^_^ffH; uHfuHR%n % LcA%%D%L%% "%0%%,%,%%1%1%% %0P%0 H`Pxp4VS_VERSION_INFO @* cE?StringFileInfo040904B0LCompanyNameMicrosoft Corporation2FileDescriptionCOM+v+FileVersion2001.12.10941.16384 (WinBuild.160101.0800)4 InternalNameMTXEX.DLL.LegalCopyright Microsoft Corporation. All rights reserved.< OriginalFilenameMTXEX.DLLj%ProductNameMicrosoft Windows Operating System> ProductVersion10.0.17763.1DVarFileInfo$Translation  hyara-4.5.3/tests/data/mtxex_modified_rsrc_rva.dll000077500000000000000000000230001501365277300221440ustar00rootroot00000000000000MZ@ !L!This program cannot be run in DOS mode. $_'K>IK>IK>I.XJI>I.XMA>IK>HW>I.XHN>I.XIJ>I.XAI>I.XJ>I.XKJ>IRichK>IPEd3l"   p`A&&<P@`p"T !.textP  `.rdata @@.data0@.pdata@@@.rsrcP @@.reloc`$@BH(uaH(H\$Ht$WH H=Y%IHHuK3H AHHuH# N\3H %tH%Hu.H $HHHt3H $H$LHH H\$0Ht$8H _H(H$H$HuH 3H(H\$Hl$Ht$ATAVAWH 3MLvDeH%0HpH;t3H5$uA$tH-#HtdH5#LLHH;r7HHtHH #H#L;uL;tLHLHHH{#H|##EHn#eH%0HpH;t3H54#u-#t _H5V #L%UI;s#uH9t HHI;rt3gH H "u HH"H9"t(H "tH"MƺIH\$@Hl$HHt$PH A_A^A\H\$Ht$WH IHuLNjHH\$0Ht$8H _HHX L@PHHVWAVHPLމ\$ ;wu9u 3ۉ\$ B;L !MtB;DƉL$I ؉D$ 3ۉ\$ s$xL$pyL$I؉D$ 3ۉ\$ s$xL$p?L$II؉D$ 3ۉ\$ s$xL$p;E33I $xL$p\$ E33I$xL$p\$ H Ht(E33I $xL$p\$ turL$I؉D$ 3ۉ\$ s$xL$pH% Ht4=et+L$I ؉D$ 3ۉ\$ s$x;w H$HPA^_^ffH; uHfuHR%n % LcA%%D%L%% "%0%%,%,%%1%1%% %0P%0 HAXSxp4VS_VERSION_INFO @* cE?StringFileInfo040904B0LCompanyNameMicrosoft Corporation2FileDescriptionCOM+v+FileVersion2001.12.10941.16384 (WinBuild.160101.0800)4 InternalNameMTXEX.DLL.LegalCopyright Microsoft Corporation. All rights reserved.< OriginalFilenameMTXEX.DLLj%ProductNameMicrosoft Windows Operating System> ProductVersion10.0.17763.1DVarFileInfo$Translation  hyara-4.5.3/tests/data/pe_imports000066400000000000000000002310001501365277300166430ustar00rootroot00000000000000MZ@ !L!This program cannot be run in DOS mode. $-,LLL'~L'~L'~L'~L9~L9~L9~LLL9~L9~LRichLPEL` @`@$(Pt<@4$@.textȶ `.rdataZ\@@.data0 @.reloctP"@BUj8Ajhp@hx@j8A]ø8AQRPh4$AZY฀8A8@t&8A@8Au h8AjAá8AS3CV;t`uXh@@u*h@V@th@V8A@tף8Aκ8A3 u;t;t2^[tV58Ah8A@^ú8A󐡠8Au3A uËU@EjPu@ujY)EDtEVWEP@}ċ#uW#U #EJ33ҋȋE t 3 u_^U <@SVWt@ vD@t:@@ @@3tB ;r J;rF(;r3_^[]EE J$B @UQQVEPEPpu E C=8Au!E8AujY)uVu uuV @ujY)^UQ8@t"R-8AuEP58ActV58Ah8A@^8AËU4SVWQM@E$MЋAYNjQ ߋq]y@E؉}y}} }3}܉}}}}u$ẺE&EPjWhWm@3E ;+E ЃE܍@u@3EtE̋PV@Ӌ\@tE̋Pj@Ӌua3SSu @uN@=@EtE̋Pj@׋u%ẺENEPjSh~m@EMLJ;uW@@}tE̋Pj@ӋE39Xt-9Xt(G<<8PEuM9L8u;|84u uE4u^uW@uN@5@EtE̋Pj@֋u%ẺEEPjShm@,uE 0@teEPjˉ}u@8_^[Vj7P,%%&j0 ^tsQh @OPYYuQGt h@YP%Yt!8uj3fP &Yjhx AjYP2ۈ]eEܡ8A3A;/uI 8AhD@h(@D!YYtEh$@h@ YY8Aو]uYM39>tVYt6WjW@+9>tVYt6a#YY #0#WV0 tku#jj\YYE5MEQPjYYËet2}u"EEMd Y_^[jV"u"tUEVH<AQAk(;tM ;J r BB ;r (;u3^]ËV_t d8AP;t3u2^ð^U}u8AM u2]c(u j Y]U=8At]Vutubt&u"h8A&Yuh8A&Yt+20 8A 8A 8A 8A 8A 8A8A^]j2jh AQeMZf9@u]<@@PEuL f9@u>E@+PQ|YYt'x$|!EE3Ɂ8ËeE2Md Y_^[Ut}u 38A]U=8At} uu'uYY]U=8AuuC% h8A%YY#E]UuYH]UeEeP0@E3EE,@1E(@1EEP$@EM3E3E3Ë 0AVWN@;tu&;uO@u G ȉ 0A_ 0A^33@ø@h8A4@ðhhj,& ujB̸8Aø8AH$HHH390AøBAøBAU$SjH@tM)j$jPE |xffftfpflfhEEDž@jPEjPE E@EE8@jXۍEEۉE@@EP<@u ujY[bj@t4MZf9u*H<ȁ9PEu f9Auytv t2h@@@UVW}7>csmu%~uF= t=!t="t=@t_3^]0w0v$̃%8ASVl Al A;sW>t @׃;r_^[SVt At A;sW>t @׃;r_^[h @d5D$l$l$+SVW0A1E3PeuEEEEdU%8A$ 0Aj H@e3SVW3ɍ}S[wO3ɉW E܋}EntelE5ineIEE5GenuE3@S[]܉Es EKS uCE%?=t#=`t=pt=Pt=`t=pu=8A=8A=8AMjXM9E|/3S[]܉sKMS ]t=8A]0A8A0A8A0Atytq3ЉEUEMj^#;uW0A8A0A t; 8A0A#;uEM#;u 0A@58A_^[339BA; 0Au(Uj@@u<@h L@PP@]U$jH@tjY):A 9A9A9A59A=9Af:Af :Af9Af9Af%9Af-9A:AE:AE:AE:AP9A:A 9A9A 9A9AjXkǀ9AjXk 0ALjX 0ALh@UVuW} t N3 8FN 3 8_^]US]VWE3ER] Cs30AVPuEu3E{ @fuZEEEECtiMGGHEtyMxHMuɄt. Eth0AVVuE_^[]ËE8csmu8=@t/h@t5@ju@֋uEM E 9x th0AV׋"E VuX sM֋INu2uuU}u ]]jh AEt~8csmuvxupx tx!t x"uUHtNQt)eRpJE1u uCYYËet@tQp@֋Md Y_^[UMU ]U} t2VW}7>csmu!~u~ t~!t~"t_^3]=pw2p$̋L$ D$׋|$<i %8As D$%0Afnfp+ρvL$$ffGfG fG0fG@fGPfG`fGpu%0As>fnfp rG stb|GD$tGutt $GuD$SVWT$D$L$URPQQh%@d50A3ĉD$d%D$0XL$,3p FT$4t;54v\ H {hCCd_^[̋L$At3D$H3Uhp pp. ]D$T$UVWS33333[_^]̋j33333USVWjRh5&@QX@_^[]Ul$RQt$ ]U@=@td E;Ar;Avj Y)]UEt= 9t/9t 9t9ubXQJC<9t/9t 9t9u FPj@Y^qY@׋EYF3_^[áA 5=AEt8uƉuM}QM}QWWPjuu u 0j _82EPEPEPVuvuEH=AƋ=AJE}PV!YYtE&Uϋ9:t@A98ulj =AE߉=APY}VY_^[ËUQES]VuW#}E t0E 2ɈM?"u ɰ"GM5tFGEP*Yt tFGEtMu< t< utFOE< t< uGM t1M E3B3G@\t"u.uMt "uG M3҄E Ht\Fut=}u< t3< t/t%tFP *Yt GtFGvtF4M _^[t!EËUVu?s9M 3u;s*M;vjPjT 3^]ËU]=Au"9=Att _u=A3Ã==At3VW%&*u$V*Yu =A3=AjYVY_^ËUQQS]3VW<=tB΍yAu+FuBjP%YYtn}RˍqAu+΍AE=t7jPYYt1SuV u@Ej0E)EY؊uW'jYY3jY_^[3PPPPP̋UVutW PYuVY_^]ËSVW==Atmt\3SSSSjPSS{(؃ tNjS,YYt7jjSVj73SSO( tSV-SZ u3 VDY_^[ËUVW~MV@UY;u_^]UE;=AtP Y]ËUE;=AtPY]h6@=Ah7@=A~5=A5=AYYá=Au V=AwUQE SVu+ƃW39u #tEt @UG;u_^[ËUVuW>t@ׅu ;u u3_^]jh ANE0+YeM *EMd Y_^[ E0,Yjh A==A3@=A3ۉ]u,=0Aσ=A;t3SSS@h>A u h$>AYE9uhX@hH@YYh`@h\@YYF9u =AFMd Y_^[ËE0 ËeB̋U3}csm]ËU}ut uYE EEMEEEjEXEEEPEPEPs}tűU*t d0@huuL@PP@u Yu@̋UQeEPh@j@t#Vh@u@t u@^}t u@ËUE=A]jjj jjj ËUjju ]ËU=A;0AuY=A]ËUjju ]ËUE=@t#=t=t jX]ù?A3]@>A@>Aø=Aø=Aj h!A:E0(YeAA5AuAAt9>t WVO5YYEMd Y_^[ E0(YËUM A=w EH#E]3]3 >A@ËU jXEMEEPEPEP@ËUV UjXP@t3t6ttP 6A^]á>AËUEttP]ù>A]ø>Aj hX!AeE0'YeM uEƋMd Y_^[ uE0'Yj h8!AeE0('YeM 4uEƋMd Y_^[ uE01'YËU ESVW00Aȋ~3؋v33;+;wƍ<0uj _;rjWS8jExMu$j~WS7jEXMىE40A}ωE+ǃ;#t}3@9I;u}E@01S)] GP V A  A3_^[ËUSW]8u0AV733υU}u;rT;Et3‹UȋȉE@U0Aʃ@33;]]]u;EtuE뢃t V 0AYPP3^_[ËUuh>AZYY]ËUjEEMXEEEPEPEPËUMu]Ë;Au 0AAA3]ËUEEMjE EXEEEPEPEPAA5Ah>A$$>AYEËV50AVk V6V-8VbV^jGYËUQh<>AMTËV5BA 5BA35BA 5=A5BA 5>A5=A 5>A^ËUVuuW`0A9>t 6W Y>_^]h@h(@G5YYËU}t=BAt;]h@h(@5YY]ËUME #Vut$t jj=YYh j^0 Qu t r=i=YY3^]jhx!Aqp te@3@ËeEv̋UQuEEY YËUUVtM t uu j^0^]W+>Gtu_u j"35tj86Y@0At"jH@tjY)jh@j j̋U]P USWMG _t A= >Au86A<6ACAVBwSPHL HHAV7,AP^u PG _[]SVL$ T$\$tP+t:uHt:Bv4u%=wڋ;uӃv#Ʃt3^[^[ËUEu]ËM UVt2ft f;1u +^]jh!AE0O YeE @HEMd Y_^[ E0] Yjh!APE0YeE HHtu`0AtQYEMd Y_^[ E0Yjh!AE0YejE 0 YYEMd Y_^[ E0Yjh!AE0=YeM A00YYEMd Y_^[ E0CYËUE3AjCHE`@EPEYj@H`0AEfHlEfrMELEEXEEEPEPEP&EEMjE EXEEEPEPEPËU}tuuIYY]UE`@t Q(EYp<Ep0Ep4Ep8Ep(Ep,Ep@EpDE`$EEMjXEEEPEPEPjEEMXEEEPEPEPËUVu~Lt(vL(FLY;AAt=5At x uP&YE FL^tPm&Y]ËSVW@P0AtP,t ux3ۋtP0AjP,thdjYYu3S5P0A,SYW5P0A,u3S5P0A,WhAAWj V\@#t_^[s̡P0AVtP",ttxnP0AjPG,tehdjYYuP5P0A#,VYA]ËUVt)\tuuuu u@փ^]u50Au350>Auu uu3PPPPPjH@tjY)VjVj# VL@PP@^ËUM3; Ũ@t'@-rAwj X]ÍDjY;#]ËŬ@]ËUVMQY0^]uX0AÃuT0AÃËUVut j3X;E r4u uFWt V*YtVj5BA@t 3^]ËU}t-uj5BA@uVj@PY^]ËUE ;Ev]]ËUVuWuu 3~~ ~3>uu 9~ u jujF3fWWjVj uu@PY4} ;G v Pu w wjVj urtHG3_^]ËUSVuuu 3ۉ^^ ^33f9u u 9^ ujFSSSSjVSu| u@PYMW} ;G v Pu7SSw wjVSu6 u@PYHG3_^[]ËUQuEPu ugËUE (Vuj^0uS3Wˉ}؉M܉]taMfE*?QP];YYuEPSSQuURPQ$ Euuu}؋M܋]+NjЉuB;ΉU#t/NjӋAEAu+MCEكBE;u݋U]3juRy uu}E}ȉEljM;Et[+׉UЉEBEBu+UBPuEE+EPQ{:urEUM MME;EuE ]0SqYE܋+‰U9U#ȉMt7ICY;u}؋uW4Y_[^SSSSS̋UQMQAuW}+ʋAЉM;vj X_SV_jSYYtWu SV9uPu+ߍ>uSP9u7]3Et VuY C0CWY^[3WWWWWT̋U0A3ʼnEM USW};t#u&jjj tFF+>vj X5Sj?S6I! uj ^ NF3jY[_^ËU]UVuuM 3S3f9u%u 9^ ujF3^zSSSSjVSu u@PYMW} ;G v P@u7SSw wjVSu u@PAQ@HPQ58>AF uF8`0At0AEu@>A@,u@>A@uE@>A@}t MPËUS]VWh3sWV{3{ { `0A+7Fu9Au_^[]ËU0A3ʼnESVuW~ Pv@3ۿÈ@;rƅ Q ;s Ƅ @;vuSvPWPjSSvWPWPWS3@SvWPWPhS3$EtLtL ˈ@;r=3ۿˍQB w LA w H AÈA;r̋M_^3[ËUuuuM EIH;Au3SVWh Yt.uvHWu'YY;uWY_^[À} uE@HKuExH`0At pHYϋE3HHM6APuEEMjEEXEEEPEPEP} rE<6Acj h"A3u}6APt9wLt wHtmYj? YuwHu] ;3t'tu`0AtVY3wHuE뭋uj7 YËƋMd Y_^[̀=D>Au<<>A`0A8>A3A4>A2A?h<>APjjD>Ah<>A\PYYËU 0A3ʼnESVu Wu{Y3ϋljM94AA0M=rP@;u&F~f~~3~ VFEPS@tuhFWPZ ^}u}Et!HtLA;v8uߍF@uvO3Gf9=@>AhFWP kE0E4AE8t5At+s4ADBA;v9u΋EGErS^FEN j4A_fRfIuV+3YM_^3[ËUVuu3mEuj^07SW}t9u rVWP 36u jP u j 9u sj"^0jX_^]ËUVuMIu EML0u39UtEp#E…t3B}^t MPËUjjuj]ËUE5;w(te*t`=+v=.vR=1tK=3tDM )=t=v=v*=t#=u؋M uuuuQP@]3UESVWr;t;t25;w#tI*tD=+v2=.v6=1t/=3=t!=v=v;t;t M 3ɋ}$##u tt'RVuuuuQP@_^[]ËUUW3f9:t!Vʍqff;u+Jf9:u^B_]ËUQSVW@3tYVWWWW+SVWW$Et6P Yt3PPuWSVPP t33WY߅tV@_^[ËUVuu( SWj=VdEYY;@E39=Au{9] t9=AtevZ8]u3jjS=A 9=Ay9=Au#jjS=A 9=AN=AE>E+PVEYYMxO9tK4YM8]u0UDA9ujQRSExEtb[E4V8]؉EP;?jRQSE+EM4\=A9] tNFu+jFPEYYtFuuV uXM+EAE#YPV+YYu8*VY!WY_[^SSSSSS̋UQW}u3_3ɋ9t @A8uVAjPYYtftPS+ߍQAu+jAPEj; <;t.7u4; uu[jY^r3PPPPP̡=A;=Au P=Y=AËUSVW==At*] SPu) u <=ttu+_^[]+U]VWH>A3jhWst?APr۰ jY2_^ËUkEH>AP`@]ËV5?At kW0>AWh@ ?Au_^ËUkEH>APd@]ËUQd0V3u@9p|EP }t3F^ËUQQSVj8j@3ۉuYYuK;tAW~ ShGPxOg 8_̍GG G _ֈ_;uɋu_SY^[ËUVut%SW;tWh@8;uVY_[^]jhX"A} r!:j ^0sƋMd Y_^[3uj~YuAA}9E|94?Au1?Auj ^uE뢡AA@AAG뻋ujlYËUEȃ?k8?AP`@]ËUEȃ?k8?APd@]ËUSVuWxg;5AAs_Ƌ?k8?AD(tD|t=u#3+tt uPjPjPj@?AL3 _^[]ËUMu Cx'; AAs?k8?AD(tD]z ]Ã=?Au ?A@3ËUHEPD@f}S]V3CƉE ;|VAAY;~W3tYEtDt?Tt6u Q@t#Njσ?k8E?ABDB(EGE;u_^[ËSVW3Njσ?k84?A~t ~tN(yF(ttjjjXP@؃t t S@3t^uN(@)u$N(N(@FBAt @GW_^[j hx"A螴jNY3ۈ]]SYuj]EËMd Y_^[Ê]jKYËV3?AtP?AYrݰ^ËUVuF ;T6AtPYF;X6AtPYF;\6AtPYF;`6AtPYF;d6AtPoYF ;h6AtP]YF$;l6AtPKYF8;6AtP9YF<;6AtP'YF@;6AtPYFD;6AtPYFH;6AtPYFL;6AtPY^]ËUVutY;H6AtPYF;L6AtPYF;P6AtPYF0;x6AtPYF4;|6AtPvY^]ËUM SVuW3?;#t6HGvY;u_^[]ËUVujVFjPF8j PFhj PjPjPQjPCDj P2j P$LjPT}Xr\g`\(^]ËUQ HLMMQPEYYËUVuw0uF;t V YtVj5BA@t  3^]ËU0A3ʼnESVWuM]uEX339E WWuuPSEJU;#t5=w1XtP&Yt Ut1RWVʶuVuujS$tuPVu @V%Y}t E䃠PǍe_^[M3JËUEt8uPY]ËUE@ H|ttttVjH(^y@6At tyt QtuLY^]ËUQSVuWtl=H6AteF|t^8uYt8uP"YYt8uPYYv|YYtE8u@-P+P+PvYjXE~(@6Att8uP>37YYEtGt 8uPYEEuVY_^[ËUMtP@t3@@]ø]ËUVut!P@tuVsVYY^]ËUMtP@tH]ø]ËUEtsH H|t t t t VjH(^y@6At t yt Qt uZY^]j h"A1exL 6APt7u=jYe5AAW=YYuE t ujYËƋMd Y_^[|̋UVu Wtt>t6@&AAu^]ËUVu tj3X;Es 3BS]Wt SY3uVSYYt;s+;VjP貭 _[^]@BAÃ%BAËUSVW};} tQt@ӄt;u u;u t.;t&~tt j@YF;u2_^[]ËUVu 9utW~t j@Y;uu_^]ËUEBA]ËUV"tu@Yt3@3^]j h"A\ejYe50A΃35BAΉuEƋMd Y_^[Ëuj Yj h"AeE0Ye50A΃35BAΉuEƋMd Y_^[ uM1YËUEHt-t! tt t3]øBA]øBA]øBA]øBA]ËUk @ E ;tU9Pt ;u3]ËU jXEMEEPEPEP ËUEBABABABA]j$h"AeeMuj[;t7Ft"Ht)HuG tt ~61V>}u]7VYYu؍x2ɈM}܃et jYMeEe?t 0A3=0AϊM}؃Euq;t tu(EHMԃ`;u@w@El@E;u"k @ k@ M;ta 0AM܉E)}ud;u.pS@Y#j[u}؀}tj_YV@Y;t tuEMԉH;u MЉH3Md Y_^[ÄtjYj jh#AE0Yeu v0[YYt2F8u@ t0YtFF EMd Y_^[ E01Yj,h8#AnE0Ye5BABA} u;tOE7PYYt7WO}}ĉEȉM̉UЋEE܉E؍EPEPEPM} EMd Y_^[ E0YËU eEeMEEEEjEXEEEPEPEP}EuEËUEtH tQu E 2]ð]ËUE$<uEu Et]2]ËUMVWq $<uGtB9A+a~1WPQYP9 ;t jX tjX!3_^]ËUVuu VY/VYu!F tVWPYYu3^]jYáBAVj^u;}ƣBAjPjBA =BAu+jV5BAjBA =BAu^W36AjhF PBA4ǃ?k8?ADt tuF8GP7Au_3^ËV'3BA4SBAY Ph@ u5BA$%BAY^ËUE P`@]ËUE Pd@]ËUMSVWt t t t t Ƌѿ#t;t;t ;u ` @ _#^[tt ;u ]Ã@] @]ËU}fEȃttt ttSV W#t&tt ;u t ;ut} E## ;V<YfEm}fEttt ttЋ#t*tt ;utut=8A]Mttttt ѻ`#t' t@t ;u   j@@[+tt +u   #}# ;Q$PEYY]Mttttt ѿ`#t' t@t ;u   @+tt +u   3 Ωt_^[ËUMtttt tVѾW#t#t;t ;u  сt u  _^t ]ËUSW} ]?uE 3fVuM蹿Exu!hBASWutuMtf3FEPPYYtBu~~);^|'39EPuvWj vEuu ;^r0t*v339E3PuEFVWj p u,*}t MP^%BA%BA3_[ËUjuu u]ËUVu ;AAtM6APu0^]ËUVu ;<>AtM6APuj^]ËUEuu]Ë@]̋U0A3ʼnEM S]VuW}u%t!PM_^3[ך]ÅtۅtDžrIΉ3+@;'7Ƌ;w/PV@Ӄ~ Ɖ;vщ;t;+߉ RBDƈJu㋝+ϋ;`ylj<0WV@Ӌ~M;t=I+׊ FuP@Ӌ~I;t7+‰ЍvL2D2Nu닝RW@Ӌ~5؋;t-+‰ЊvL2D2Nu닅ډ;v>$;s#WV@~BI;wWV@Ӌ~ۋ$+؉;vWS@փً;rJt++؊RLDJu답;;s<$+ȉ;v!WQ@ӋtD$+ȉ;vWQ@ӋtՋʋ+΋+;|=;sD A;sD;st @;s ϋvt UMS]Vuuu9u t'Kj^0^[]ÅtE tu3u+ًWuBt'u ΊBt tuɋMu_uu E jPDXj"qU]BUV3PPPPPPPPU I t $u t $sF ^ËUju u ]ËU}uAy3Vu u%]9ur3EuMǷMVytJ9Uw Du+‹փ+J}t MP^ËUQQ0A3ʼnESVuW~VuY;Yp|}$u Ex}$39E(jjVuPW=ЃUXH;#t5=ws9܅tPhYt U3ۅRSVujW}3PPPPPWSuu Ut8E ;3QQQPuWSuu 6H;#t/;w8t`PYtK3t:jjjVWuSuu 6t3PP9E u:PPVWPu$l u,WY3SYƍe_^[M3ǒu uWoYԋUuM荵u(Eu$u uuuuu P$}t MP&3ɄËU= >Au]juu u]ËUMSVWu Eu3MtU u%]h;v=M}􋟤uuVPRQ[-wPRPQhESP u 趽p}t MP_^[ËU0S3V]Љ]ԉ]؉]܉]]]]u]]]PEPu蓿 u(PEPu zu u Vu@؀}tV腽Y}t uvY^[ËUMu3]S] VW}Bw 3Fw ƒ+u tu_^[]ËUSVW3;+‹jU4hAu ty^~;~ЃlA_^[]ËU}tuYx=s H@]3]ËU}u$\]uj5BA@]ËUW}u u *Y$Vu u WKYv%λ 3^_]PtVYtVWj5BA@tj hX#AA3uE0YuE 8ǃ?k8?AD(t!WrYP@u-@1 uEƋMd Y_^[ uM1eYËUVuu YxE;5AAs=Ƌփ?k8?AD(t"EuEMEuPEPEP芺 ¹^ËU0A3ʼnEE Ѓ?k8SV?AW}}UDEEljM؉E@3ۉESMMNj]u]IM};EM؈EыE]E?AE3UԋÃ.щU8t@|U+׉E܅ED.X7A@E+E܉E;U܋M1D5F;|uԋM؅~VEWPM؃ U܋}?A\0.F;|}Euԍ|E3}Q|@]PE܍EPEP UX7AAM;3txt}@QPE܍EPEP uOT-tD.EEEjT-EPCEMf9H},GE;E1jEWPM E}jWEP0 (SSjEGPu܍E}PSuS E̅SMQPEPu@u+uEu9E} u4j XSfEЍEPjEPu@}EFu;}M|~%E ?A;΋uCD1.u;|u}uP~u؋E ?A;ΈD.C;|ыUM؊]?A\.?AL-F@E8]t EPEuM3ͥ_^[覊ËUQSVu3W} EljE;s?SOYf;u(F uj [S7Yf;uFF;}r@_^[ËUQVuWV YtU?k8?A|0(}fE;r׋+MjPVPW@tC;rM;r@M_^3[ ËU-0A3ʼnEM U?k8SV?AuWDM3;P;s! u j ZffM;rjjhU QP+PPjhu tQ3ۅt5j+QPP@t&;rˋ+EF;F@M_^3[׆jhx#A规uuҲ ݲ ;5AAƃ?k8M?AD(tiVY}e?AMD(uy [ uu VQ }E )u}VY * bMd Y_^[ËU(MMSVuW} }u α ٱƋ?k8U?AE\)tu ШtED( tjjjV VYt9t"ˀuEWP uEWVPE ?AE|(}FÃt.tuEWVPuEWVPuEWVP롋L}3jEPuuQ@u @E؍u؍}䥥EueEt*j^;u萰 r0PBY}EM?AD(@t?tQ3 p+E3_^[jh#AہejYej^u;5BAtYBAtJ@ tBA4: YtE䡤BA Ph@BA4,YBA$FEEMd Y_^[j=YËUVuW~  t%tvίY!3FF_^]ËUMu 5 8x$; AAs?k8?AD(@] 83]jh#A蚀=8A|[E@tJ=P7AtAeUE:E8t 8t33@Ëe%P7AeUǃ࿉EUMd Y_^[ËUQ}EËUQQ}M Ef#M#E f fMmEËUM t -A]t-A]t -A]t ؛ t]ËUQ}EËUu M}Ehu0腝 }t MPËUM9u3@yujX 38A]UQuEuu P)ЃwMvEtfËUQQ}SVW} ?]uthWMhuPEWPЃt\tOMv+v3KM  ffu] +u;Y33fE 8}*=3 t:uCCWMuPWj&u=*_^[ËUE `*]ËUM38t ;E t@<u]ËU= >AVuH}u׫>} t9uv谫^]O juu u^]ËUW}uo觪S] uM腪|Vuv*bXu3PuMȡEMGU C+u tMuـ}t M샡P^[_ËU,0A3ʼnEESVuE؋E EԋEEW}}~VWsYEY *] ~ SPSYY  E$u E؋@E$t;CMQP@~4}r&}EtHt:r:8ujX~7}r)}Et u܊Ht:r:\8u3@U3WWVuj u$ZE؅3 Q;#tA=w"ĉEPEYElj}uPVuu$jVݻWWSuj VĻE Q;#t2=w!t\PYtGt6uVSuju$^t]WWWuVuSuu]VY]SY jl3e_^[M3 |ËUuMu$Eu uuuuu PD }t MPËUQQVuWVY;u˧ NjMuMQuu P@u@PeYӋEU#;tNjE΃?k8 ?Ad1(_^ËUuuu un]ËUQ}tEPEjP tfEøËUVuuGRF W t9VvV[VVP"y~t v,fYV&Y_^]jh#ASxuuu菦ǥYYtvt VwYu6.YM_3^d][ËUQQE]EËUE tjt3@]ètjtjX]]ËSQQUkl$0A3ʼnEVs CWVPs u&ePCPCPs C sPEP|s s^Yvt)t%CV\$\$C$s Wc$W)$VCYYM_3^c][ËUS]VtEtjY#EtjYEjfEY #tT=t7=t;ubM A{LHM {,A2M zAM zAAEE WDEPQQ$U U}3GgAu EeEfE;}0E+ʋUEtuGEEt EUu؃}EtE 3G_tjYtE t j Y3^[ËUjuuuuu u]ËUE3S3CHEW HEH Mt E Xt EHt EHt EHt EHMVu 3A1AM3A1AM3A1AM3A1AM3A#1A2tMI tEH tEH tEH  tE X  #t5=t"=t ;u)E!MM E #t =t ;u"E M MEM31E X } t,E` EEXE X`E]``EXP:MA A EEXE X`M]A`A`EXPYEPjjW@MAt&At&At&At&At&ߋt5t"t u( % % !tt u!#  # } ^tAPAP_[]ËUEtwފ"]ъ!]ËUU 3ɋ9ňAt@| ŌAMtUEEEEEEEVuEE hu(EE$uEEPBp uVUYE^hu(u9E ËUEVDz 3Wf}ǩuzM UuthپS3AuCEuɉM yM NEtf}Uf#f}[t fEEjQQ$1 #jQQ$ _E0^]ËUQQMEE%] fMEËU} Euu@]Á} u ujX]fMf#f;ujf;uE utj3]ËUfMff#f;u3EQQ$|YYttt3@]jjX]ø]ɁfuE u}tɃᐍ]EDz ɃA@]Ɂ]UE3SVWH<AYt} p ;r H;r B(;r3_^[]Ujh$Ah @dPSVW0A1E3PEdeEh@|tTE-@Ph@Rt:@$ЃEMd Y_^[]ËE3Ɂ8ËeE3Md Y_^[]UMMZf9uA<8PEu f9Hu]3]QL$+ȃ YQL$+ȃ YQL$+#ȋ%;r Y$-̃=8Ar_D$ fnpۋT$#+o fftftff#uf~3:E3D$ST$t :tYtQu WV ؋ ~333ƃu!%t%uu^_[3ÍB[ËB:t6t:t't:tt:tt^_B[ÍB^_[ÍB^_[ÍB^_[UQ=8A|f}t }uT]E?t?uét*uéué uøËE%% &&,&<&J&^&p&&&&&&& '('F'X't''*'''''(6(B(P(^(h(z(((((((() )),)<)N)X)d)p)))))))**,*<*N*Z*h*|******@ @Y@@@g@|@;@;@ߩ@}@HelloHelloUSER32.dllKERNEL32.DLLAcquireSRWLockExclusiveReleaseSRWLockExclusive0AA@8A9AP9At"@(@4@<@H@ T@ `@ l@ |@ @@ @ @@ @ @ @@@@@@@@@@@ @@@@@ @$@(@,@0@4@8@<@@@D@H@L@P@T@X@\@`@d@h@l@p@t@x@|@@@@ @ @@@@@@ @,@L@l@@#@@ @@&8@T@d@h@p@@#@@ @@@@%,@$T@%|@+@@ @" @(8@*d@@ @@ @@@@@@@@$@X@P@0@@0@__based(__cdecl__pascal__stdcall__thiscall__fastcall__vectorcall__clrcall__eabi__swift_1__swift_2__ptr64__restrict__unalignedrestrict( new delete=>><<!==!=[]operator->*++---+&->*/%<<=>>=,()~^|&&||*=+=-=/=%=>>=<<=&=|=^=`vftable'`vbtable'`vcall'`typeof'`local static guard'`string'`vbase destructor'`vector deleting destructor'`default constructor closure'`scalar deleting destructor'`vector constructor iterator'`vector destructor iterator'`vector vbase constructor iterator'`virtual displacement map'`eh vector constructor iterator'`eh vector destructor iterator'`eh vector vbase constructor iterator'`copy constructor closure'`udt returning'`EH`RTTI`local vftable'`local vftable constructor closure' new[] delete[]`omni callsig'`placement delete closure'`placement delete[] closure'`managed vector constructor iterator'`managed vector destructor iterator'`eh vector copy constructor iterator'`eh vector vbase copy constructor iterator'`dynamic initializer for '`dynamic atexit destructor for '`vector copy constructor iterator'`vector vbase copy constructor iterator'`managed vector copy constructor iterator'`local static thread guard'operator "" operator co_awaitoperator<=> Type Descriptor' Base Class Descriptor at ( Base Class Array' Class Hierarchy Descriptor' Complete Object Locator'`anonymous namespace'T@@@api-ms-win-core-fibers-l1-1-1api-ms-win-core-synch-l1-2-0kernel32api-ms-FlsAllocFlsFreeFlsGetValueFlsSetValueInitializeCriticalSectionEx   mscoree.dllCorExitProcess?@?@u@Eu@@@c@d@u@u@@@H@I@h@h@:@@"[@@/@@@@@?@?@@        ! 5A CPR S WY l m pr  )   Y* @,@8@D@ja-JPzh-CNko-KRzh-TW@@@@@@@@@@@@@@@@@ @$@(@,@0@4@8@<@@@D@L@X@`@$@h@p@x@@@@@@@@@@@@@@@@@@(@8@H@\@p@@@@@@@@@@@@@@@@@$@@0@<@H@X@l@|@@@@@@@@SunMonTueWedThuFriSatSundayMondayTuesdayWednesdayThursdayFridaySaturdayJanFebMarAprMayJunJulAugSepOctNovDecJanuaryFebruaryMarchAprilJuneJulyAugustSeptemberOctoberNovemberDecemberAMPMMM/dd/yydddd, MMMM dd, yyyyHH:mm:ssSunMonTueWedThuFriSatSundayMondayTuesdayWednesdayThursdayFridaySaturdayJanFebMarAprMayJunJulAugSepOctNovDecJanuaryFebruaryMarchAprilJuneJulyAugustSeptemberOctoberNovemberDecemberAMPMMM/dd/yydddd, MMMM dd, yyyyHH:mm:ssen-US ((((( H   !"#$%&'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~ukh@T@@@(@@@@@P@@@@p@@@@@(@p@api-ms-win-core-datetime-l1-1-1api-ms-win-core-file-l1-2-2api-ms-win-core-localization-l1-2-1api-ms-win-core-localization-obsolete-l1-2-0api-ms-win-core-processthreads-l1-1-2api-ms-win-core-string-l1-1-0api-ms-win-core-sysinfo-l1-2-1api-ms-win-core-winrt-l1-1-0api-ms-win-core-xstate-l2-1-0api-ms-win-rtcore-ntuser-window-l1-1-0api-ms-win-security-systemfunctions-l1-1-0ext-ms-win-ntuser-dialogbox-l1-1-0ext-ms-win-ntuser-windowstation-l1-1-0advapi32ntdllapi-ms-win-appmodel-runtime-l1-1-2user32ext-ms-AreFileApisANSICompareStringExLCMapStringExLocaleNameToLCIDAppPolicyGetProcessTerminationMethodh@p@x@@@@@@ @ @ @ @ @@@@@@@@@@ @(@0@8@@@H@P@X@ `@!h@"@#p@$x@%@&@'@)@*@+@,@-@/@6@7@8@9@>@?@@@A@C@D@F@G @I(@J0@K8@N@@OH@PP@VX@W`@Zh@ep@x@|@@@D@@@@@ @ @ @ @@@ @ @8@@$@0@<@H@T@`@l@x@@@@ @!@"@#@$@%@&@'@)@*@+ @,,@-D@/P@2\@4h@5t@6@7@8@9@:@;@>@?@@@A@C@D@E@F(@G4@I@@JL@KX@Ld@Np@O|@P@R@V@W@Z@e@k@l@@@,@@ @ (@ 4@@@L@X@d@p@@,@;@>@C@k@ @ @ @ @ @ (@ 4@; L@k X@h@t@@ @ @ @@;@@@@ @ @ @@;,@<@ H@ T@ `@l@;@@ @ @@;@ @ @ @; A$A $ A $,A;$8A(HA (TA (`A,lA ,xA ,A0A 0A 0A4A 4A 4A8A 8A<A <A@A @A D A H,A L8A PDA|PA|`Aarbgcazh-CHScsdadeelenesfifrhehuisitjakonlnoplptroruhrsksqsvthtruridbesletlvltfavihyazeumkafkafohimskkkyswuzttpagutateknmrsamnglkoksyrdivar-SAbg-BGca-EScs-CZda-DKde-DEel-GRfi-FIfr-FRhe-ILhu-HUis-ISit-ITnl-NLnb-NOpl-PLpt-BRro-ROru-RUhr-HRsk-SKsq-ALsv-SEth-THtr-TRur-PKid-IDuk-UAbe-BYsl-SIet-EElv-LVlt-LTfa-IRvi-VNhy-AMaz-AZ-Latneu-ESmk-MKtn-ZAxh-ZAzu-ZAaf-ZAka-GEfo-FOhi-INmt-MTse-NOms-MYkk-KZky-KGsw-KEuz-UZ-Latntt-RUbn-INpa-INgu-INta-INte-INkn-INml-INmr-INsa-INmn-MNcy-GBgl-ESkok-INsyr-SYdiv-MVquz-BOns-ZAmi-NZar-IQde-CHen-GBes-MXfr-BEit-CHnl-BEnn-NOpt-PTsr-SP-Latnsv-FIaz-AZ-Cyrlse-SEms-BNuz-UZ-Cyrlquz-ECar-EGzh-HKde-ATen-AUes-ESfr-CAsr-SP-Cyrlse-FIquz-PEar-LYzh-SGde-LUen-CAes-GTfr-CHhr-BAsmj-NOar-DZzh-MOde-LIen-NZes-CRfr-LUbs-BA-Latnsmj-SEar-MAen-IEes-PAfr-MCsr-BA-Latnsma-NOar-TNen-ZAes-DOsr-BA-Cyrlsma-SEar-OMen-JMes-VEsms-FIar-YEen-CBes-COsmn-FIar-SYen-BZes-PEar-JOen-TTes-ARar-LBen-ZWes-ECar-KWen-PHes-CLar-AEes-UYar-BHes-PYar-QAes-BOes-SVes-HNes-NIes-PRzh-CHTsrx@B@,Aqh@AAAAAAAAA A A A$ AC0 A< AH A@)T Al Akp@! Acp@ AD A} Ax@ AE@ AG A@ AH@ A A AI A Ap@A, A@< AJ@H AT A` Al Ax A A A A A A AK A A@ A A A A A A, A8 AD AP A\ Ah At A A A A A A A@# Ae@* Al@& Ah@ AL@. As@  A A A( AM4 A@ AX@>L A @7X A@ d AN@/p At0@| A AZ@ AO@( Ajh@ Aa@ AP@ A AQ@ AR@- Ar@1 Ax8@: A@`@? A AS@2( Ay@%4 Ag@$@ AfL A@+X Amd AP@=p A@@;| A@0 A Aw Au AU@ A AT A@ A@6 A~@ AV@AW AA(A8A @HAX(@TAYH@<`AlAxAvA8@A[x@"AdAAAAAA@@A\`AA,ADA\AH@tAA]@3Azh@@A(@8A0@9AP@A^AnX@A_@5A|@ Ab`@A`@4A A{@'8AiDAoPA`ApA|AAAAFApaf-zaar-aear-bhar-dzar-egar-iqar-joar-kwar-lbar-lyar-maar-omar-qaar-saar-syar-tnar-yeaz-az-cyrlaz-az-latnbe-bybg-bgbn-inbs-ba-latnca-escs-czcy-gbda-dkde-atde-chde-dede-lide-ludiv-mvel-gren-auen-bzen-caen-cben-gben-ieen-jmen-nzen-phen-tten-usen-zaen-zwes-ares-boes-cles-coes-cres-does-eces-eses-gtes-hnes-mxes-nies-paes-pees-pres-pyes-sves-uyes-veet-eeeu-esfa-irfi-fifo-fofr-befr-cafr-chfr-frfr-lufr-mcgl-esgu-inhe-ilhi-inhr-bahr-hrhu-huhy-amid-idis-isit-chit-itja-jpka-gekk-kzkn-inkok-inko-krky-kglt-ltlv-lvmi-nzmk-mkml-inmn-mnmr-inms-bnms-mymt-mtnb-nonl-benl-nlnn-nons-zapa-inpl-plpt-brpt-ptquz-boquz-ecquz-pero-roru-rusa-inse-fise-nose-sesk-sksl-sisma-nosma-sesmj-nosmj-sesmn-fisms-fisq-alsr-ba-cyrlsr-ba-latnsr-sp-cyrlsr-sp-latnsv-fisv-sesw-kesyr-syta-inte-inth-thtn-zatr-trtt-ruuk-uaur-pkuz-uz-cyrluz-uz-latnvi-vnxh-zazh-chszh-chtzh-cnzh-hkzh-mozh-sgzh-twzu-zaD0log10??33CONOUT$??BBxPD?X1=??0C0CΗ5@=)d U5j%5j?~@5wzA.lzZ?ܧ׹fq @ @6C ??exp@@@P@0@5h!?5h!??@  ?5h!>@@loglog10exppowasinacossqrt? |?Q-8>=޶W?0 k8=ޮp? x9=>.ښ?pn5=Yح? Q*=c??b6=Y?T?=>?W!=@-32?Dz=p(?vP(=`?US?>=e?g7=`ŀ'?bͬ/=^s?}#=Jwk?zn=N ָ?LN9=@$"3?5Wg4p6=T?Nv$^)=&?.)<lB?M%=`j?w*= <śm?E2=ެ> ?E=t?? =OQ?w(@ <0?Ac 0=Pyp?dry?=St)?4K >=$?QhBC .=0 ub?-0=?a>-?=?Й,<(lX ?T@b ==P?3h,%=f??# =V ?ߠϡ6=Y?z $=G? $l35=@n?[+3=Rŷ?sdLi==p|?rx"#2=@.?|U2=lԝ?rF=a? 4=Y?sl׼#{ =`~R=?.i1=,? =vX?=p?h}s"= E[ ?%S#[k=7H?j=!V1?}a2=jq?20J5=?5=x¾/@?"B <1=iz?\-!y!=X0z?~b>==:? #.X'=HBO&?(~=xbb? .=Cq?y7i9+= v?:=0 ?2ض8=xPD?X1=??Q?Q?????????]?]?P?P? ? ?U?U?(?(?`?`?_?_?????z?z?1?1?p?p???(e?(e?@#?@#???`?`?hk?hk?,?,?x?x?????N?N?x?x?p?p???~?~?HN?HN???????p?p?Xi?Xi???????????8?8?s?s?pI?pI?&?&?????o?o? *? *???`?`?Z?Z???0?0???PY?PY???`?`???pm?pm?/?/??????0A4A$A(ApAxA!A8A @AAAHAAA A A AAAAAAAA"A#A$A%A&Asinhcoshtanhatanatan2sincostanceilfloorfabsmodfldexp_cabs_hypotfmodfrexp_y0_y1_yn_logb_nextafterO_`   %ȶ.text$mn.idata$5.00cfg.CRT$XCA .CRT$XCAA$.CRT$XCZ(.CRT$XIA,.CRT$XIAA0.CRT$XIAC4.CRT$XICD.CRT$XIZH.CRT$XPAL.CRT$XPXT.CRT$XPXAX.CRT$XPZ\.CRT$XTA`.CRT$XTZpL.rdata.rdata$sxdata.rdata$zzzdbgh .rtc$IAAl .rtc$IZZp .rtc$TAAt .rtc$TZZx .xdata$x4$ .didat$2T$ .didat$3t$ .didat$4$.didat$6$ .didat$7$.idata$2$.idata$3$.idata$4% .idata$60.data8.didat$58L .bssE@Y@H@[@"@"@8@9@'8@\;@=@<@vA@zA@C@D@CD@D@Z@KV@e@h@`p@(w@y@w@z@f{@@F@@М@@X@Ȫ@I@\@88t$$$$MessageBoxAMessageBeep$'%% &&,&<&J&^&p&&&&&&& '('F'X't''*'''''(6(B(P(^(h(z(((((((() )),)<)N)X)d)p)))))))**,*<*N*Z*h*|******dRaiseExceptiondGetLastErrorGetSystemInfoVirtualProtectVirtualQueryFreeLibrary{GetModuleHandleWGetProcAddressLoadLibraryExAOQueryPerformanceCounterGetCurrentProcessIdGetCurrentThreadIdGetSystemTimeAsFileTimefInitializeSListHeadIsDebuggerPresentUnhandledExceptionFilterqSetUnhandledExceptionFilterGetStartupInfoWIsProcessorFeaturePresentGetCurrentProcessTerminateProcessKERNEL32.dllRtlUnwind4SetLastError4EnterCriticalSectionLeaveCriticalSectionDeleteCriticalSectionbInitializeCriticalSectionAndSpinCountTlsAllocTlsGetValueTlsSetValueTlsFreeLoadLibraryExWGetStdHandleWriteFilewGetModuleFileNameWaExitProcesszGetModuleHandleExWGetCommandLineAGetCommandLineWHHeapAllocLHeapFreexFindClose~FindFirstFileExWFindNextFileWIsValidCodePageGetACPGetOEMCPGetCPInfoMultiByteToWideCharWideCharToMultiByte:GetEnvironmentStringsWFreeEnvironmentStringsWSetEnvironmentVariableWNSetStdHandleQGetFileTypeGetStringTypeWCompareStringWLCMapStringWGetProcessHeapQHeapSizeOHeapReAllocFlushFileBuffersGetConsoleOutputCPGetConsoleMode%SetFilePointerExCreateFileWCloseHandleWriteConsoleW DecodePointerDN@   abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`y!@~ڣ @ڣ AϢ[@~QQ^ _j21~@@6A@6A@6A@6A@6AH6A@@P@5A`0AC6ABABABABABABABABABA6ABABABABABABABA..   uA@&@\0000'040B0M0]0c0m0000000000001 111C1^111111112B2R2v222222222(3p333333344#4H4b4h4}444445)5E555!6L6a6f6k666668.8a888888888888999$99999:!:*:7:M:::::::; ;;";;<<8M>U>>>>>>>>? ??"?D?K?Z?d?w????????????????? 0 000&0/040:0D0N0^0n0~00 1111112w2233P455*616[6`666666 77:7D7N7\7w77777777848H8Y8e8t88888 99909=9F9K9P9k9u9999999999999:%:5:t::::a<<<<<<<=K=P=T=X=\=0001'131F1M1U1m1{11111 22222244445%5C6667$7)73787C7N7[7i777768C8R8g8q8888888889999999::":b:h:|:::::::::;;$;;<>>>?o??????@040?0G0R0X0c0i0w0000000Q1n122p2x22334R445,5566666(7=7O7\7u7777778.858V88888888 99.9:&:3:d:::::; ;;O;;;;; <<%<??`C000000 11#11=3C3Q3`333444!4(4.4I4P4 5:5555555566,6B6}66667!7:7r777708B8v888 989J9\9n999999999:1:C:U:g:y:;; <<==> ?7?g??p00=00000000 111#1(1-1R1n1|11111122Q2i2y222222393I3N3S3n3x333333333334 44.4=4H4M4R4s444455 5+5R5d5p55556O666666777U7`7777772878<8A8J8 99t9}9999=::::<<<===+=;=P=g========>D02333333<4456g667j78B8: =d>>"?M?~?????)0>0O0001:1\111@2233 4U4u4445J5i5{555556[6667D7k77F8v888889X:::%;\;};;;;;;;d>/>;>J>]???t0$080C001\111v23&3633444444=5H5N5W5555555636|6666667z78t88=9\99:<40>8><>@>D>H>L>P>T>\>`>d>h>l>p>t>x>>>>>>>>0000P0T0X0\0`0d0h0l0p0t0x0|0000000000000000000000000000000011 11111 1$1(1,1014181<1@1D1H1L1P1T1X1\1`1d1h1l1p1t1x1|11111111111111;; ;$;(;,;0;4;8;<;@;D;H;L;P;T;X;\;`;d;L0T0\0d0l0t0|000000000000000001 111$1,141<1D1L1T1\1d1l1t1|111111111111111112 222$2,242<2D2L2T2\2d2l2t2|222222222222222223 333$3,343<3D3L3T3\3d3l3t3|333333333333333334 444$4,444<4D4L4T4\4d4l4t4|444444444444444445 555$5,545<5D5L5T5\5d5l5t5|555555555555555556 666$6,646<6D6L6T6\6d6l6t6|666666666666666667 777$7,747<7D7L7T7\7d7h1p1x111111111111111112222 2(20282@2H2P2X2`2h2p2x222222222222222223333 3(30383@3H3P3X3`3h3p3x333333333333333334444 4(40484@4H4P4X4`4h4p4x444444444444444445555 5(50585@5H5P5X5`5h5p5x555555555555555556666 6(60686@6H6P6X6`6h6p6x666666666666666667777 7(70787@7H7P7X7`7h7p7x777777777777777778888 8(80888@8H8P8X8`8h8p8x88L2222;;;;;;;;;;;;;;;< <<<$<,<4<<@@.tls@@@/4PB@B/19lnH@B/31%0&@B/45/`0@B/57  @@B/702@B/81/0@B/92N@Bff.@H(H41H4H4H\4H?3f8MZuHcP@C {S H fDA@HALH)LLHELIL EIIAH)LLHEL9IL-L$H}I)INd@KAHHLE9L9uDH #HEH "HXHeVHt,$L$ HL$ HT$(T$0\$8D$@АHXff.@H V| H(=/=vXs? w:H"HcH1ҹ H E1DH(f=vFE1=t=1ҹj HHE1DH(E1=ADH(1ҹ% HAHcE1TD1ҹ Ht~Ht) E1)f.ADAD E1fy E1f Y E1fATUWVSH aHƋ`Tu%Ht H !FTiHtH [^_]A\@H9U0E1H*THH-H HH)HH7f. IH oP SPHHH)SCI t#L;HuMiD  IH To_BfDATH HỈ CCG ==vTs? w:HHcH1ҹHH A\@=v;=t=u41ҹHHtи@=tHRHtLH A\HB(y1H A\1ҹ3HteHtиL1ҹ HtOHt иf ATWVSH(H pTF]HCTHt2H=]H5L] IօuMt HCLH[HuH %TH([^_A\H%9]DWVSH SHօu H [^_f9HHt<8H SHp\HSH SHSHC\1H [^_ÃSH mS˅u1H [H iS?\H V%.V%V%V%U%U%U%U%U%U%U%U%~U%nU%^U%NU%>U%.U%U%U%T[,@ -@+@+@+@+@,@2-+] fHello@u@`p@@@@u@@@Unknown errorArgument domain error (DOMAIN)Overflow range error (OVERFLOW)Partial loss of significance (PLOSS)Total loss of significance (TLOSS)The result is too small to be represented (UNDERFLOW)Argument singularity (SIGN)_matherr(): %s in %s(%g, %g) (retval=%g) x,L\l Vn_sign_posn? WBXunsigned char __lc_time_data_PHNDLRB]_XCPT_ACTIOND BXcptNumESigNumF ]XcptActionG M_XcptActTabJB_XcptActTabCountK]_XcptActTabSizeL]_First_FPE_IndxM]_Num_FPEN] _EXCEPTION_RECORD r ExceptionCode ExceptionFlags [ ! ExceptionAddress j  NumberParameters  ExceptionInformation  r_CONTEXT% P1Home Z P2Home Z  P3Home Z  P4Home Z  P5Home Z P6Home Z ( ContextFlags 0 MxCsr 4 SegCs 8 SegDs : SegEs < SegFs > SegGs @ SegSs B EFlags D Dr0 Z H Dr1 Z P Dr2 Z X Dr3 Z ` Dr6 Z h Dr7 Z p Rax Z x Rcx Z Rdx Z Rbx Z Rsp Z Rbp Z Rsi Z Rdi Z R8 Z R9 Z R10 Z R11 Z R12 Z R13 Z R14 Z R15 Z Rip Z BVectorRegister { VectorControl Z  DebugControl Z  LastBranchToRip Z  LastBranchFromRip Z  LastExceptionToRip Z  LastExceptionFromRip Z WINBOOL ]BYTEWORDBDWORDfloat LPBYTE __imp__pctype+ __imp__wctype; __imp__pwctypeG M B __newclmapPM __newcumapQM __ptlocinfoRp__ptmbcinfoS8__globallocalestatusT]__locale_changedU]__initiallocinfoV(__initiallocalestructinfoW__imp___mb_cur_maxsigned charshort intULONG_PTR 1.DWORD64 .PVOIDrCHARLONGdy LPSTRP HANDLErLONGLONG%ULONGLONG. _LIST_ENTRYd Flinke Blinkf LIST_ENTRYg _GUID |Data1 Data2 BData3 BData4 |GUID 0IID XCLSID `FMTID gEXCEPTION_ROUTINE)]j yj PEXCEPTION_ROUTINE *_M128Aj(` Lowk Highl M128Am0`` __onexit_t 2]doublelong double =s_sys_errlist &_sys_nerr $]!__imp___argc !__imp___argv HNs!__imp___wargv "kqy!__imp__environ BH!__imp__wenviron Gk!__imp__pgmptr NN!__imp__wpgmptr Sq!__imp__osplatform X !__imp__osver ] !__imp__winver b !__imp__winmajor g !__imp__winminor l _amblksiz 5_XMM_SAVE_AREA32 ControlWord StatusWord  TagWord  Reserved1  ErrorOpcode  ErrorOffset  ErrorSelector Reserved2  DataOffset  DataSelector  Reserved3  MxCsr  MxCsr_Mask "FloatRegisters p "XmmRegisters  Reserved4 XMM_SAVE_AREA32c#1"Header1"Legacyp "Xmm0`"Xmm1`"Xmm2`"Xmm3`"Xmm4`"Xmm5`Xmm6`Xmm7`Xmm8` Xmm9`0Xmm10`@Xmm11`PXmm12``Xmm13`pXmm14`Xmm15``B${%FltSave%FloatSave&`PCONTEXTyH EXCEPTION_RECORD PEXCEPTION_RECORD  _EXCEPTION_POINTERS .[  ContextRecord '[(Next0(prev0 _EXCEPTION_REGISTRATION_RECORD)4)[' (Handler (handler '(FiberDataj (Version _NT_TIB8# ExceptionList. StackBase j  StackLimit j  SubSystemTib j ) ArbitraryUserPointer! j ( Self"0NT_TIB#PNT_TIB$!GUID_MAX_POWER_SAVINGS!GUID_MIN_POWER_SAVINGS!GUID_TYPICAL_POWER_SAVINGS!NO_SUBGROUP_GUID!ALL_POWERSCHEMES_GUID !GUID_POWERSCHEME_PERSONALITY!!GUID_ACTIVE_POWERSCHEME"!GUID_IDLE_RESILIENCY_SUBGROUP#!GUID_IDLE_RESILIENCY_PERIOD$!GUID_DISK_COALESCING_POWERDOWN_TIMEOUT%!GUID_EXECUTION_REQUIRED_REQUEST_TIMEOUT&!GUID_VIDEO_SUBGROUP'!GUID_VIDEO_POWERDOWN_TIMEOUT(!GUID_VIDEO_ANNOYANCE_TIMEOUT)!GUID_VIDEO_ADAPTIVE_PERCENT_INCREASE*!GUID_VIDEO_DIM_TIMEOUT+!GUID_VIDEO_ADAPTIVE_POWERDOWN,!GUID_MONITOR_POWER_ON-!GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS.!GUID_DEVICE_POWER_POLICY_VIDEO_DIM_BRIGHTNESS/!GUID_VIDEO_CURRENT_MONITOR_BRIGHTNESS0!GUID_VIDEO_ADAPTIVE_DISPLAY_BRIGHTNESS1!GUID_CONSOLE_DISPLAY_STATE2!GUID_ALLOW_DISPLAY_REQUIRED3!GUID_VIDEO_CONSOLE_LOCK_TIMEOUT4!GUID_ADAPTIVE_POWER_BEHAVIOR_SUBGROUP5!GUID_NON_ADAPTIVE_INPUT_TIMEOUT6!GUID_DISK_SUBGROUP7!GUID_DISK_POWERDOWN_TIMEOUT8!GUID_DISK_IDLE_TIMEOUT9!GUID_DISK_BURST_IGNORE_THRESHOLD:!GUID_DISK_ADAPTIVE_POWERDOWN;!GUID_SLEEP_SUBGROUP<!GUID_SLEEP_IDLE_THRESHOLD=!GUID_STANDBY_TIMEOUT>!GUID_UNATTEND_SLEEP_TIMEOUT?!GUID_HIBERNATE_TIMEOUT@!GUID_HIBERNATE_FASTS4_POLICYA!GUID_CRITICAL_POWER_TRANSITIONB!GUID_SYSTEM_AWAYMODEC!GUID_ALLOW_AWAYMODED!GUID_ALLOW_STANDBY_STATESE!GUID_ALLOW_RTC_WAKEF!GUID_ALLOW_SYSTEM_REQUIREDG!GUID_SYSTEM_BUTTON_SUBGROUPH!GUID_POWERBUTTON_ACTIONI!GUID_SLEEPBUTTON_ACTIONJ!GUID_USERINTERFACEBUTTON_ACTIONK!GUID_LIDCLOSE_ACTIONL!GUID_LIDOPEN_POWERSTATEM!GUID_BATTERY_SUBGROUPN!GUID_BATTERY_DISCHARGE_ACTION_0O!GUID_BATTERY_DISCHARGE_LEVEL_0P!GUID_BATTERY_DISCHARGE_FLAGS_0Q!GUID_BATTERY_DISCHARGE_ACTION_1R!GUID_BATTERY_DISCHARGE_LEVEL_1S!GUID_BATTERY_DISCHARGE_FLAGS_1T!GUID_BATTERY_DISCHARGE_ACTION_2U!GUID_BATTERY_DISCHARGE_LEVEL_2V!GUID_BATTERY_DISCHARGE_FLAGS_2W!GUID_BATTERY_DISCHARGE_ACTION_3X!GUID_BATTERY_DISCHARGE_LEVEL_3Y!GUID_BATTERY_DISCHARGE_FLAGS_3Z!GUID_PROCESSOR_SETTINGS_SUBGROUP[!GUID_PROCESSOR_THROTTLE_POLICY\!GUID_PROCESSOR_THROTTLE_MAXIMUM]!GUID_PROCESSOR_THROTTLE_MINIMUM^!GUID_PROCESSOR_ALLOW_THROTTLING_!GUID_PROCESSOR_IDLESTATE_POLICY`!GUID_PROCESSOR_PERFSTATE_POLICYa!GUID_PROCESSOR_PERF_INCREASE_THRESHOLDb!GUID_PROCESSOR_PERF_DECREASE_THRESHOLDc!GUID_PROCESSOR_PERF_INCREASE_POLICYd!GUID_PROCESSOR_PERF_DECREASE_POLICYe!GUID_PROCESSOR_PERF_INCREASE_TIMEf!GUID_PROCESSOR_PERF_DECREASE_TIMEg!GUID_PROCESSOR_PERF_TIME_CHECKh!GUID_PROCESSOR_PERF_BOOST_POLICYi!GUID_PROCESSOR_PERF_BOOST_MODEj!GUID_PROCESSOR_IDLE_ALLOW_SCALINGk!GUID_PROCESSOR_IDLE_DISABLEl!GUID_PROCESSOR_IDLE_STATE_MAXIMUMm!GUID_PROCESSOR_IDLE_TIME_CHECKn!GUID_PROCESSOR_IDLE_DEMOTE_THRESHOLDo!GUID_PROCESSOR_IDLE_PROMOTE_THRESHOLDp!GUID_PROCESSOR_CORE_PARKING_INCREASE_THRESHOLDq!GUID_PROCESSOR_CORE_PARKING_DECREASE_THRESHOLDr!GUID_PROCESSOR_CORE_PARKING_INCREASE_POLICYs!GUID_PROCESSOR_CORE_PARKING_DECREASE_POLICYt!GUID_PROCESSOR_CORE_PARKING_MAX_CORESu!GUID_PROCESSOR_CORE_PARKING_MIN_CORESv!GUID_PROCESSOR_CORE_PARKING_INCREASE_TIMEw!GUID_PROCESSOR_CORE_PARKING_DECREASE_TIMEx!GUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_DECREASE_FACTORy!GUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_THRESHOLDz!GUID_PROCESSOR_CORE_PARKING_AFFINITY_WEIGHTING{!GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_DECREASE_FACTOR|!GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_THRESHOLD}!GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_WEIGHTING~!GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_THRESHOLD!GUID_PROCESSOR_PARKING_CORE_OVERRIDE!GUID_PROCESSOR_PARKING_PERF_STATE!GUID_PROCESSOR_PARKING_CONCURRENCY_THRESHOLD!GUID_PROCESSOR_PARKING_HEADROOM_THRESHOLD!GUID_PROCESSOR_PERF_HISTORY!GUID_PROCESSOR_PERF_LATENCY_HINT!GUID_PROCESSOR_DISTRIBUTE_UTILITY!GUID_SYSTEM_COOLING_POLICY!GUID_LOCK_CONSOLE_ON_WAKE!GUID_DEVICE_IDLE_POLICY!GUID_ACDC_POWER_SOURCE!GUID_LIDSWITCH_STATE_CHANGE!GUID_BATTERY_PERCENTAGE_REMAINING!GUID_GLOBAL_USER_PRESENCE!GUID_SESSION_DISPLAY_STATUS!GUID_SESSION_USER_PRESENCE!GUID_IDLE_BACKGROUND_TASK!GUID_BACKGROUND_TASK_NOTIFICATION!GUID_APPLAUNCH_BUTTON!GUID_PCIEXPRESS_SETTINGS_SUBGROUP!GUID_PCIEXPRESS_ASPM_POLICY!GUID_ENABLE_SWITCH_FORCED_SHUTDOWN!PPM_PERFSTATE_CHANGE_GUID!PPM_PERFSTATE_DOMAIN_CHANGE_GUID!PPM_IDLESTATE_CHANGE_GUID!PPM_PERFSTATES_DATA_GUID!PPM_IDLESTATES_DATA_GUID!PPM_IDLE_ACCOUNTING_GUID!PPM_IDLE_ACCOUNTING_EX_GUID!PPM_THERMALCONSTRAINT_GUID!PPM_PERFMON_PERFSTATE_GUID!PPM_THERMAL_POLICY_CHANGE_GUID _IMAGE_DOS_HEADER@qK- e_magicr e_cblps  e_cpt  e_crlcu  e_cparhdrv  e_minallocw e_maxallocx e_ssy  e_spz  e_csum{  e_ip|  e_cs}  e_lfarlc~  e_ovno  e_res K- e_oemid $ e_oeminfo & e_res2 [-( e_lfanew < [- k- IMAGE_DOS_HEADER+PIMAGE_DOS_HEADER-+ _IMAGE_FILE_HEADER{. Machine NumberOfSections  TimeDateStamp  PointerToSymbolTable  NumberOfSymbols SizeOfOptionalHeader  Characteristics IMAGE_FILE_HEADER- _IMAGE_DATA_DIRECTORY. VirtualAddress Size IMAGE_DATA_DIRECTORY . _IMAGE_OPTIONAL_HEADER$0 Magic& ' ( ) * + , 8-  BaseOfData. / 0 1 $2 (3 *4 ,5 .6 07 28 4,9 8 : < ; @~< Dk= Fl> H? L@ PA TB XGC \D0`.0PIMAGE_OPTIONAL_HEADER32E 1. _IMAGE_OPTIONAL_HEADER64W2 MagicX Y Z [ \ ] ^ 8_ ` a b $c (d *e ,f .g 0h 2i 4,j 8 k < l @~m Dkn Flo Hp Pq Xr `s hGt lu0pIMAGE_OPTIONAL_HEADER64v1PIMAGE_OPTIONAL_HEADER64v 31_IMAGE_NT_HEADERS643 Signature FileHeader{. OptionalHeader2PIMAGE_NT_HEADERS643%3PIMAGE_NT_HEADERS!3PIMAGE_TLS_CALLBACK3334j  j _RTL_CRITICAL_SECTION_DEBUG055 Type6 CreatorBackTraceIndex7  CriticalSection8%5 ProcessLocksList9 EntryCount: ContentionCount; $ Flags< ( CreatorBackTraceIndexHigh= , SpareWORD> . _RTL_CRITICAL_SECTION(P5 DebugInfoQ#5 LockCountR  RecursionCountS OwningThreadT  LockSemaphoreU  SpinCountVH 5PRTL_CRITICAL_SECTION_DEBUG?#54RTL_CRITICAL_SECTIONW55 6.HINSTANCE__36unused]HINSTANCEE6 6CRITICAL_SECTION 5PTOP_LEVEL_EXCEPTION_FILTER5LPTOP_LEVEL_EXCEPTION_FILTER%d6_STARTUPINFOAh>8cb? lpReserved@ lpDesktopA lpTitleB dwXC dwYD $dwXSizeE (dwYSizeF ,dwXCountCharsG 0dwYCountCharsH 4dwFillAttributeI 8dwFlagsJ <wShowWindowK @cbReserved2L BlpReserved2M HhStdInputN PhStdOutputO XhStdErrorP `STARTUPINFOAQ6STARTUPINFOh8!VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN!VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFTRPC_IF_HANDLEBr*tagCOINITBASE8+COINITBASE_MULTITHREADEDIWinTypesBase_v0_1_c_ifspec*8IWinTypesBase_v0_1_s_ifspec+8IID_IUnknownaIID_AsyncIUnknown!IID_IClassFactory8!IID_IMarshal!IID_INoMarshal!IID_IAgileObject!IID_IAgileReference>!IID_IMarshal2!IID_IMalloc!IID_IStdMarshalInfo!IID_IExternalConnection!IID_IMultiQIb!IID_AsyncIMultiQI!IID_IInternalUnknown!IID_IEnumUnknownb!IID_IEnumString!IID_ISequentialStreamp!IID_IStream!IID_IRpcChannelBuffer% !IID_IRpcChannelBuffer2 !IID_IAsyncRpcChannelBuffer! !IID_IRpcChannelBuffer3 !IID_IRpcSyntaxNegotiate !IID_IRpcProxyBuffer !IID_IRpcStubBufferI !IID_IPSFactoryBuffer !IID_IChannelHookH !IID_IClientSecurity(!IID_IServerSecurity!IID_IRpcOptions0!IID_IGlobalOptions!IID_ISurrogate!IID_IGlobalInterfaceTablet!IID_ISynchronize!IID_ISynchronizeHandleF!IID_ISynchronizeEvent!IID_ISynchronizeContainer!IID_ISynchronizeMutexJ!IID_ICancelMethodCalls!IID_IAsyncManager!IID_ICallFactoryw!IID_IRpcHelper!IID_IReleaseMarshalBuffers&!IID_IWaitMultiplex!IID_IAddrTrackingControl!IID_IAddrExclusionControl,!IID_IPipeByte!IID_IPipeLong!IID_IPipeDoubleE!IID_IComThreadingInfo!IID_IProcessInitControl1!IID_IFastRundown!IID_IMarshalingStream!IID_ICallbackWithNoReentrancyToApplicationSTAzGUID_NULL CATID_MARSHALERIID_IRpcChannelIID_IRpcStubIID_IStubManagerIID_IRpcProxyIID_IProxyManagerIID_IPSFactoryIID_IInternalMonikerIID_IDfReserved1IID_IDfReserved2IID_IDfReserved3CLSID_StdMarshalCLSID_AggStdMarshalCLSID_StdAsyncActManagerIID_IStubIID_IProxyIID_IEnumGenericIID_IEnumHolderIID_IEnumCallback IID_IOleManager!IID_IOlePresObj"IID_IDebug#IID_IDebugStream$CLSID_PSGenObject%CLSID_PSClientSite&CLSID_PSClassObject'CLSID_PSInPlaceActive(CLSID_PSInPlaceFrame)CLSID_PSDragDrop*CLSID_PSBindCtx+CLSID_PSEnumerators,CLSID_StaticMetafile-CLSID_StaticDib.CID_CDfsVolume/CLSID_DCOMAccessControl0CLSID_GlobalOptions1CLSID_StdGlobalInterfaceTable2CLSID_ComBinding3CLSID_StdEvent4CLSID_ManualResetEvent5CLSID_SynchronizeContainer6CLSID_AddrControl7CLSID_CCDFormKrnl8CLSID_CCDPropertyPage9CLSID_CCDFormDialog:CLSID_CCDCommandButton;CLSID_CCDComboBox<CLSID_CCDTextBox=CLSID_CCDCheckBox>CLSID_CCDLabel?CLSID_CCDOptionButton@CLSID_CCDListBoxACLSID_CCDScrollBarBCLSID_CCDGroupBoxCCLSID_CCDGeneralPropertyPageDCLSID_CCDGenericPropertyPageECLSID_CCDFontPropertyPageFCLSID_CCDColorPropertyPageGCLSID_CCDLabelPropertyPageHCLSID_CCDCheckBoxPropertyPageICLSID_CCDTextBoxPropertyPageJCLSID_CCDOptionButtonPropertyPageKCLSID_CCDListBoxPropertyPageLCLSID_CCDCommandButtonPropertyPageMCLSID_CCDComboBoxPropertyPageNCLSID_CCDScrollBarPropertyPageOCLSID_CCDGroupBoxPropertyPagePCLSID_CCDXObjectPropertyPageQCLSID_CStdPropertyFrameRCLSID_CFormPropertyPageSCLSID_CGridPropertyPageTCLSID_CWSJArticlePageUCLSID_CSystemPageVCLSID_IdentityUnmarshalWCLSID_InProcFreeMarshalerXCLSID_Picture_MetafileYCLSID_Picture_EnhMetafileZCLSID_Picture_Dib[GUID_TRISTATE\IWinTypes_v0_1_c_ifspec)8IWinTypes_v0_1_s_ifspec*8,VARENUMJ+VT_EMPTY+VT_NULL+VT_I2+VT_I4+VT_R4+VT_R8+VT_CY+VT_DATE+VT_BSTR+VT_DISPATCH +VT_ERROR +VT_BOOL +VT_VARIANT +VT_UNKNOWN +VT_DECIMAL+VT_I1+VT_UI1+VT_UI2+VT_UI4+VT_I8+VT_UI8+VT_INT+VT_UINT+VT_VOID+VT_HRESULT+VT_PTR+VT_SAFEARRAY+VT_CARRAY+VT_USERDEFINED+VT_LPSTR+VT_LPWSTR+VT_RECORD$+VT_INT_PTR%+VT_UINT_PTR&+VT_FILETIME@+VT_BLOBA+VT_STREAMB+VT_STORAGEC+VT_STREAMED_OBJECTD+VT_STORED_OBJECTE+VT_BLOB_OBJECTF+VT_CFG+VT_CLSIDH+VT_VERSIONED_STREAMI-VT_BSTR_BLOB-VT_VECTOR-VT_ARRAY -VT_BYREF@-VT_RESERVED-VT_ILLEGAL-VT_ILLEGALMASKED-VT_TYPEMASK!IID_IMallocSpy!IID_IBindCtx:!IID_IEnumMonikerJ !IID_IRunnableObject !IID_IRunningObjectTable!!IID_IPersisti"!IID_IPersistStream"!IID_IMonikerj#!IID_IROTDataX%!IID_IEnumSTATSTG%!IID_IStorageX&!IID_IPersistFileA(!IID_IPersistStorage(!IID_ILockBytes)!IID_IEnumFORMATETC*!IID_IEnumSTATDATAl+!IID_IRootStorage,!IID_IAdviseSink,!IID_AsyncIAdviseSinks-!IID_IAdviseSink2.!IID_AsyncIAdviseSink2./!IID_IDataObject/!IID_IDataAdviseHolder1!IID_IMessageFilter1!FMTID_SummaryInformation]2!FMTID_DocSummaryInformation_2!FMTID_UserDefinedPropertiesa2!FMTID_DiscardableInformationc2!FMTID_ImageSummaryInformatione2!FMTID_AudioSummaryInformationg2!FMTID_VideoSummaryInformationi2!FMTID_MediaFileSummaryInformationk2!IID_IClassActivators2!IID_IFillLockBytes2!IID_IProgressNotify3!IID_ILayoutStorage3!IID_IBlockingLock4!IID_ITimeAndNoticeControl4!IID_IOplockStorageN5!IID_IDirectWriterLock5!IID_IUrlMonM6!IID_IForegroundTransfer6!IID_IThumbnailExtractor7!IID_IDummyHICONIncluder7!IID_IProcessLock7!IID_ISurrogateServiceH8!IID_IInitializeSpy8!IID_IApartmentShutdown9IID_IOleAdviseHolder!IID_IOleCache!IID_IOleCache2!IID_IOleCacheControl!IID_IParseDisplayName!IID_IOleContainerp!IID_IOleClientSite!IID_IOleObject!IOLETypes_v0_0_c_ifspec8!IOLETypes_v0_0_s_ifspec8!IID_IOleWindow!IID_IOleLinkk!IID_IOleItemContainer9!IID_IOleInPlaceUIWindow!IID_IOleInPlaceActiveObjectX!IID_IOleInPlaceFrame !IID_IOleInPlaceObject !IID_IOleInPlaceSitef !IID_IContinue, !IID_IViewObject{ !IID_IViewObject2 !IID_IDropSource9 !IID_IDropTarget !IID_IDropSourceNotify0!IID_IEnumOLEVERBIID_IServiceProviderT!IOleAutomationTypes_v1_0_c_ifspecd8!IOleAutomationTypes_v1_0_s_ifspece8!IID_ICreateTypeInfo!IID_ICreateTypeInfo2 !IID_ICreateTypeLib!IID_ICreateTypeLib2!IID_IDispatchl!IID_IEnumVARIANT !IID_ITypeComp !IID_ITypeInfo] !IID_ITypeInfo2 !IID_ITypeLib!IID_ITypeLib2!IID_ITypeChangeEvents!IID_IErrorInfol!IID_ICreateErrorInfo!IID_ISupportErrorInfod!IID_ITypeFactory!IID_ITypeMarshal!IID_IRecordInfo!IID_IErrorLog!IID_IPropertyBag__MIDL_itf_msxml_0000_v0_0_c_ifspec8__MIDL_itf_msxml_0000_v0_0_s_ifspec8LIBID_MSXML!IID_IXMLDOMImplementation!IID_IXMLDOMNode(!IID_IXMLDOMDocumentFragment!IID_IXMLDOMDocumentg!IID_IXMLDOMNodeListv!IID_IXMLDOMNamedNodeMap!IID_IXMLDOMCharacterData!IID_IXMLDOMAttribute!IID_IXMLDOMElement!IID_IXMLDOMText!IID_IXMLDOMComment&!IID_IXMLDOMProcessingInstruction!IID_IXMLDOMCDATASection!IID_IXMLDOMDocumentType!IID_IXMLDOMNotation !IID_IXMLDOMEntity!IID_IXMLDOMEntityReference!IID_IXMLDOMParseErrorb !IID_IXTLRuntime !DIID_XMLDOMDocumentEvents> !CLSID_DOMDocument] !CLSID_DOMFreeThreadedDocumenta !IID_IXMLHttpRequesth !CLSID_XMLHTTPRequest !IID_IXMLDSOControl !CLSID_XMLDSOControl !IID_IXMLElementCollection !IID_IXMLDocumentK !IID_IXMLDocument2 !IID_IXMLElement% !IID_IXMLElement2 !IID_IXMLAttribute !IID_IXMLError !CLSID_XMLDocument/ !CLSID_SBS_StdURLMonikerK!CLSID_SBS_HttpProtocolL!CLSID_SBS_FtpProtocolM!CLSID_SBS_GopherProtocolN!CLSID_SBS_HttpSProtocolO!CLSID_SBS_FileProtocolP!CLSID_SBS_MkProtocolQ!CLSID_SBS_UrlMkBindCtxR!CLSID_SBS_SoftDistExtS!CLSID_SBS_CdlProtocolT!CLSID_SBS_ClassInstallFilterU!CLSID_SBS_InternetSecurityManagerV!CLSID_SBS_InternetZoneManagerW!IID_IAsyncMoniker`!CLSID_StdURLMonikera!CLSID_HttpProtocolb!CLSID_FtpProtocolc!CLSID_GopherProtocold!CLSID_HttpSProtocole!CLSID_FileProtocolf!CLSID_MkProtocolg!CLSID_StdURLProtocolh!CLSID_UrlMkBindCtxi!CLSID_CdlProtocolj!CLSID_ClassInstallFilterk!IID_IAsyncBindCtxl!IID_IPersistMoniker!IID_IMonikerProp!IID_IBindProtocol!IID_IBindingh!IID_IBindStatusCallback!IID_IBindStatusCallbackEx!IID_IAuthenticate!IID_IAuthenticateEx!IID_IHttpNegotiate^!IID_IHttpNegotiate2!IID_IHttpNegotiate3: !IID_IWinInetFileStream !IID_IWindowForBindingUI !IID_ICodeInstallz !IID_IUri !IID_IUriContainer !IID_IUriBuilder !IID_IUriBuilderFactory^!IID_IWinInetInfo!IID_IHttpSecurity6!IID_IWinInetHttpInfo!IID_IWinInetHttpTimeouts!IID_IWinInetCacheHintso!IID_IWinInetCacheHints2!SID_BindHost4!IID_IBindHost>!IID_IInternet`!IID_IInternetBindInfo!IID_IInternetBindInfoEx'!IID_IInternetProtocolRoot!IID_IInternetProtocolI!IID_IInternetProtocolEx!IID_IInternetProtocolSink!IID_IInternetProtocolSinkStackable1!IID_IInternetSession!IID_IInternetThreadSwitch\!IID_IInternetPriority!IID_IInternetProtocolInfoF!CLSID_InternetSecurityManagerw!CLSID_InternetZoneManagerx!CLSID_PersistentZoneIdentifier{!IID_IInternetSecurityMgrSite!IID_IInternetSecurityManager!IID_IInternetSecurityManagerEx!IID_IInternetSecurityManagerEx2!IID_IZoneIdentifier!IID_IInternetHostSecurityManager!GUID_CUSTOM_LOCALMACHINEZONEUNLOCKEDX!IID_IInternetZoneManager!IID_IInternetZoneManagerEx!IID_IInternetZoneManagerEx2 !CLSID_SoftDistExt!!IID_ISoftDistExt!!IID_ICatalogFileInfox"!IID_IDataFilter"!IID_IEncodingFilterFactoryp#!GUID_CUSTOM_CONFIRMOBJECTSAFETY#!IID_IWrappedProtocol#!IID_IGetBindHandleR$!IID_IBindCallbackRedirect$!IID_IPropertyStorage!IID_IPropertySetStorage!IID_IEnumSTATPROPSTG*!IID_IEnumSTATPROPSETSTGIID_StdOleGUID_DEVINTERFACE_DISK GUID_DEVINTERFACE_CDROM GUID_DEVINTERFACE_PARTITION GUID_DEVINTERFACE_TAPE GUID_DEVINTERFACE_WRITEONCEDISK GUID_DEVINTERFACE_VOLUME GUID_DEVINTERFACE_MEDIUMCHANGER GUID_DEVINTERFACE_FLOPPY GUID_DEVINTERFACE_CDCHANGER GUID_DEVINTERFACE_STORAGEPORT GUID_DEVINTERFACE_COMPORT GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR _SCARD_IO_REQUEST!CgdwProtocol! cbPciLength! SCARD_IO_REQUEST!fCgg_rgSCardT0Pci"%.\gg_rgSCardT1Pci"%=\gg_rgSCardRawPci"%L\gIID_IPrintDialogCallback#IID_IPrintDialogServices#_commode$].@$% hosfhnd$& osfile$' pipech$( lockinitflag$) ] lock$*K6/textmode$+ 8/unicode$, 8pipech2$- h9hioinfo$.ghhhh__imp___badioinfo$Dh__imp___pioinfo$Ih_dowildcard$f]_newmode$g]__imp___winitenv$jk__imp___initenv$oH.$ kinewmode$ ]_startupinfo$Pi0$i+__uninitialized+__initializing+__initialized1$ii__native_startup_state$+i__native_startup_lock$jj2__native_dllmain_reason$ __native_vcclrit_reason$ _PVFV%_PIFV%__security_cookie&__imp__HUGE'j!signgam']_TCHAR(__image_base__/k-__imp__fmode5__imp__commode6_fmode9 ]ij)k__xi_aB$k__xi_zC$k[jRk__xc_aD$Gk__xc_zE$Gk__dyn_tls_init_callbackO"3mingw_app_typeQ ]3__mingw_winmain_hInstanceS 36 hy@3__mingw_winmain_lpCmdLineT k `y@j3__mingw_winmain_nShowCmdU 0@4argcW ] (p@4argv]N  p@4envp^N p@5argreta ]4mainretb ] p@4managedappc ]  p@4has_cctord ] p@4startinfoeki p@__mingw_oldexcpt_handlerf%63mingw_pcinitrij  @3mingw_pcppinits[j @_MINGW_INSTALL_DEBUG_MATHERRu ]!mingw_initltsdrot_force^ ]!mingw_initltsdyn_force_ ]!mingw_initltssuo_force` ]!mingw_initcharmaxa ]6__mingw_module_is_dll p@7atexit ] @pn8func9)@v:RR;duplicate_ppstrings n=l ?check_managed_appd]Io=pDOSHeaderf-=pPEHeaderg3=pNTHeader32h0=pNTHeader64i2@__tmainCRTStartup]@6sAlpszCommandLine kE=4StartupInfo+8~AinDoubleQuote B@rAlock_free rA9Afiberid rAnested ]Cu@@pDlv@@"IEvjhFvGv@pEXvEFvH1vIpn@@uHqEnEn/-FnTRFn}wFnJn@@*qFnKJ@vLV@voq:Rt9j@v:Xt9'@v:R|IuM@M@ qEu*(HuL@vq:R ML@r:R0:Q2:X0KQ@ wL^@w*rNRKm@#wLy@/wVr:R @K~@;wK@GwK@SwK@ewL!@swr:ROL?@wrNRNQKu@wL@wrNRNQK@w9i@w:R~OmainCRTStartup]@"^sAret]RNK@wK @IoOWinMainCRTStartup]@"sAret]K@wK@IoPpre_cpp_init0@I(t9t@w:R (p@:Q  p@:X p@:w p@@pre_c_init]@tGn@tQRnF oFoF3oUSL@wt:R1K@wK@wL@wt:R29@wNRP__mingw_invalidParameterHandler}@uSexpression}2RSfunction~QSfileXSlineYSpReserved _TEBTNtCurrentTeb"uuU_InterlockedExchangePointer.ruW_cexit_cexit&@ Vexitexit  Z77+Y  &{YII$Y$Y   Yyy$uY'OeGNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/gccmain.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt@charlong long unsigned intlong long intptrdiff_t]#wchar_tgshort unsigned intintlong intpthreadlocinfo(djthreadlocaleinfostruct`,9 lc_codepagea lc_collate_cpa lc_handleq lc_id $ lc_categoryH lc_clike9 mb_cur_max9  lconv_intl_refcount[ lconv_num_refcount[ lconv_mon_refcount[  lconv( ctype1_refcount[0 ctype18 pctype@ pclmapH pcumapP lc_time_currXpthreadmbcinfo%,2 threadmbcinfostruct localeinfo_struct locinfoL mbcinfo_locale_tstructG tagLC_ID wLanguage wCountry wCodePageLC_ID O locale O wlocaleU, [ wrefcount [9unsigned intlong unsigned int lconv4unsigned char __lc_time_data_PHNDLRB"9_XCPT_ACTIOND nXcptNumESigNumF 9XcptActionG "y_XcptActTabJn_XcptActTabCountK9_XcptActTabSizeL9_First_FPE_IndxM9_Num_FPEN9DWORDfloata__imp__pctype+__imp__wctype;__imp__pwctypeGZO__newclmapPZ__newcumapQZ__ptlocinfoRL__ptmbcinfoS__globallocalestatusT9__locale_changedU9__initiallocinfoV(j__initiallocalestructinfoW__imp___mb_cur_max[signed charshort int_GUIDData1Data2Data3Data4GUIDUIIDXCLSID`FMTIDgdoublelong doubleO*_sys_errlist&_sys_nerr$9__imp___argc[__imp___argv}O__imp___wargv"U__imp__environB}__imp__wenvironG__imp__pgmptrN__imp__wpgmptrS__imp__osplatformX__imp__osver]__imp__winverb__imp__winmajorg__imp__winminorl_amblksiz5aGUID_MAX_POWER_SAVINGS GUID_MIN_POWER_SAVINGS GUID_TYPICAL_POWER_SAVINGS NO_SUBGROUP_GUID ALL_POWERSCHEMES_GUID GUID_POWERSCHEME_PERSONALITY !GUID_ACTIVE_POWERSCHEME "GUID_IDLE_RESILIENCY_SUBGROUP #GUID_IDLE_RESILIENCY_PERIOD $GUID_DISK_COALESCING_POWERDOWN_TIMEOUT %GUID_EXECUTION_REQUIRED_REQUEST_TIMEOUT &GUID_VIDEO_SUBGROUP 'GUID_VIDEO_POWERDOWN_TIMEOUT (GUID_VIDEO_ANNOYANCE_TIMEOUT )GUID_VIDEO_ADAPTIVE_PERCENT_INCREASE *GUID_VIDEO_DIM_TIMEOUT +GUID_VIDEO_ADAPTIVE_POWERDOWN ,GUID_MONITOR_POWER_ON -GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS .GUID_DEVICE_POWER_POLICY_VIDEO_DIM_BRIGHTNESS /GUID_VIDEO_CURRENT_MONITOR_BRIGHTNESS 0GUID_VIDEO_ADAPTIVE_DISPLAY_BRIGHTNESS 1GUID_CONSOLE_DISPLAY_STATE 2GUID_ALLOW_DISPLAY_REQUIRED 3GUID_VIDEO_CONSOLE_LOCK_TIMEOUT 4GUID_ADAPTIVE_POWER_BEHAVIOR_SUBGROUP 5GUID_NON_ADAPTIVE_INPUT_TIMEOUT 6GUID_DISK_SUBGROUP 7GUID_DISK_POWERDOWN_TIMEOUT 8GUID_DISK_IDLE_TIMEOUT 9GUID_DISK_BURST_IGNORE_THRESHOLD :GUID_DISK_ADAPTIVE_POWERDOWN ;GUID_SLEEP_SUBGROUP <GUID_SLEEP_IDLE_THRESHOLD =GUID_STANDBY_TIMEOUT >GUID_UNATTEND_SLEEP_TIMEOUT ?GUID_HIBERNATE_TIMEOUT @GUID_HIBERNATE_FASTS4_POLICY AGUID_CRITICAL_POWER_TRANSITION BGUID_SYSTEM_AWAYMODE CGUID_ALLOW_AWAYMODE DGUID_ALLOW_STANDBY_STATES EGUID_ALLOW_RTC_WAKE FGUID_ALLOW_SYSTEM_REQUIRED GGUID_SYSTEM_BUTTON_SUBGROUP HGUID_POWERBUTTON_ACTION IGUID_SLEEPBUTTON_ACTION JGUID_USERINTERFACEBUTTON_ACTION KGUID_LIDCLOSE_ACTION LGUID_LIDOPEN_POWERSTATE MGUID_BATTERY_SUBGROUP NGUID_BATTERY_DISCHARGE_ACTION_0 OGUID_BATTERY_DISCHARGE_LEVEL_0 PGUID_BATTERY_DISCHARGE_FLAGS_0 QGUID_BATTERY_DISCHARGE_ACTION_1 RGUID_BATTERY_DISCHARGE_LEVEL_1 SGUID_BATTERY_DISCHARGE_FLAGS_1 TGUID_BATTERY_DISCHARGE_ACTION_2 UGUID_BATTERY_DISCHARGE_LEVEL_2 VGUID_BATTERY_DISCHARGE_FLAGS_2 WGUID_BATTERY_DISCHARGE_ACTION_3 XGUID_BATTERY_DISCHARGE_LEVEL_3 YGUID_BATTERY_DISCHARGE_FLAGS_3 ZGUID_PROCESSOR_SETTINGS_SUBGROUP [GUID_PROCESSOR_THROTTLE_POLICY \GUID_PROCESSOR_THROTTLE_MAXIMUM ]GUID_PROCESSOR_THROTTLE_MINIMUM ^GUID_PROCESSOR_ALLOW_THROTTLING _GUID_PROCESSOR_IDLESTATE_POLICY `GUID_PROCESSOR_PERFSTATE_POLICY aGUID_PROCESSOR_PERF_INCREASE_THRESHOLD bGUID_PROCESSOR_PERF_DECREASE_THRESHOLD cGUID_PROCESSOR_PERF_INCREASE_POLICY dGUID_PROCESSOR_PERF_DECREASE_POLICY eGUID_PROCESSOR_PERF_INCREASE_TIME fGUID_PROCESSOR_PERF_DECREASE_TIME gGUID_PROCESSOR_PERF_TIME_CHECK hGUID_PROCESSOR_PERF_BOOST_POLICY iGUID_PROCESSOR_PERF_BOOST_MODE jGUID_PROCESSOR_IDLE_ALLOW_SCALING kGUID_PROCESSOR_IDLE_DISABLE lGUID_PROCESSOR_IDLE_STATE_MAXIMUM mGUID_PROCESSOR_IDLE_TIME_CHECK nGUID_PROCESSOR_IDLE_DEMOTE_THRESHOLD oGUID_PROCESSOR_IDLE_PROMOTE_THRESHOLD pGUID_PROCESSOR_CORE_PARKING_INCREASE_THRESHOLD qGUID_PROCESSOR_CORE_PARKING_DECREASE_THRESHOLD rGUID_PROCESSOR_CORE_PARKING_INCREASE_POLICY sGUID_PROCESSOR_CORE_PARKING_DECREASE_POLICY tGUID_PROCESSOR_CORE_PARKING_MAX_CORES uGUID_PROCESSOR_CORE_PARKING_MIN_CORES vGUID_PROCESSOR_CORE_PARKING_INCREASE_TIME wGUID_PROCESSOR_CORE_PARKING_DECREASE_TIME xGUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_DECREASE_FACTOR yGUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_THRESHOLD zGUID_PROCESSOR_CORE_PARKING_AFFINITY_WEIGHTING {GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_DECREASE_FACTOR |GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_THRESHOLD }GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_WEIGHTING ~GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_THRESHOLD GUID_PROCESSOR_PARKING_CORE_OVERRIDE GUID_PROCESSOR_PARKING_PERF_STATE GUID_PROCESSOR_PARKING_CONCURRENCY_THRESHOLD GUID_PROCESSOR_PARKING_HEADROOM_THRESHOLD GUID_PROCESSOR_PERF_HISTORY GUID_PROCESSOR_PERF_LATENCY_HINT GUID_PROCESSOR_DISTRIBUTE_UTILITY GUID_SYSTEM_COOLING_POLICY GUID_LOCK_CONSOLE_ON_WAKE GUID_DEVICE_IDLE_POLICY GUID_ACDC_POWER_SOURCE GUID_LIDSWITCH_STATE_CHANGE GUID_BATTERY_PERCENTAGE_REMAINING GUID_GLOBAL_USER_PRESENCE GUID_SESSION_DISPLAY_STATUS GUID_SESSION_USER_PRESENCE GUID_IDLE_BACKGROUND_TASK GUID_BACKGROUND_TASK_NOTIFICATION GUID_APPLAUNCH_BUTTON GUID_PCIEXPRESS_SETTINGS_SUBGROUP GUID_PCIEXPRESS_ASPM_POLICY GUID_ENABLE_SWITCH_FORCED_SHUTDOWN PPM_PERFSTATE_CHANGE_GUID PPM_PERFSTATE_DOMAIN_CHANGE_GUID PPM_IDLESTATE_CHANGE_GUID PPM_PERFSTATES_DATA_GUID PPM_IDLESTATES_DATA_GUID PPM_IDLE_ACCOUNTING_GUID PPM_IDLE_ACCOUNTING_EX_GUID PPM_THERMALCONSTRAINT_GUID PPM_PERFMON_PERFSTATE_GUID PPM_THERMAL_POLICY_CHANGE_GUID VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT RPC_IF_HANDLE BtagCOINITBASEaeCOINITBASE_MULTITHREADEDIWinTypesBase_v0_1_c_ifspec *IWinTypesBase_v0_1_s_ifspec +IID_IUnknown aIID_AsyncIUnknown IID_IClassFactory 8IID_IMarshalIID_INoMarshalIID_IAgileObjectIID_IAgileReference>IID_IMarshal2IID_IMallocIID_IStdMarshalInfoIID_IExternalConnectionIID_IMultiQIbIID_AsyncIMultiQIIID_IInternalUnknownIID_IEnumUnknownbIID_IEnumStringIID_ISequentialStreampIID_IStreamIID_IRpcChannelBuffer% IID_IRpcChannelBuffer2 IID_IAsyncRpcChannelBuffer! IID_IRpcChannelBuffer3 IID_IRpcSyntaxNegotiate IID_IRpcProxyBuffer IID_IRpcStubBufferI IID_IPSFactoryBuffer IID_IChannelHookH IID_IClientSecurity(IID_IServerSecurityIID_IRpcOptions0IID_IGlobalOptionsIID_ISurrogateIID_IGlobalInterfaceTabletIID_ISynchronizeIID_ISynchronizeHandleFIID_ISynchronizeEventIID_ISynchronizeContainerIID_ISynchronizeMutexJIID_ICancelMethodCallsIID_IAsyncManagerIID_ICallFactorywIID_IRpcHelperIID_IReleaseMarshalBuffers&IID_IWaitMultiplexIID_IAddrTrackingControlIID_IAddrExclusionControl,IID_IPipeByteIID_IPipeLongIID_IPipeDoubleEIID_IComThreadingInfoIID_IProcessInitControl1IID_IFastRundownIID_IMarshalingStreamIID_ICallbackWithNoReentrancyToApplicationSTAzGUID_NULL CATID_MARSHALERIID_IRpcChannelIID_IRpcStubIID_IStubManagerIID_IRpcProxyIID_IProxyManagerIID_IPSFactoryIID_IInternalMonikerIID_IDfReserved1IID_IDfReserved2IID_IDfReserved3CLSID_StdMarshalCLSID_AggStdMarshalCLSID_StdAsyncActManagerIID_IStubIID_IProxyIID_IEnumGenericIID_IEnumHolderIID_IEnumCallback IID_IOleManager!IID_IOlePresObj"IID_IDebug#IID_IDebugStream$CLSID_PSGenObject%CLSID_PSClientSite&CLSID_PSClassObject'CLSID_PSInPlaceActive(CLSID_PSInPlaceFrame)CLSID_PSDragDrop*CLSID_PSBindCtx+CLSID_PSEnumerators,CLSID_StaticMetafile-CLSID_StaticDib.CID_CDfsVolume/CLSID_DCOMAccessControl0CLSID_GlobalOptions1CLSID_StdGlobalInterfaceTable2CLSID_ComBinding3CLSID_StdEvent4CLSID_ManualResetEvent5CLSID_SynchronizeContainer6CLSID_AddrControl7CLSID_CCDFormKrnl8CLSID_CCDPropertyPage9CLSID_CCDFormDialog:CLSID_CCDCommandButton;CLSID_CCDComboBox<CLSID_CCDTextBox=CLSID_CCDCheckBox>CLSID_CCDLabel?CLSID_CCDOptionButton@CLSID_CCDListBoxACLSID_CCDScrollBarBCLSID_CCDGroupBoxCCLSID_CCDGeneralPropertyPageDCLSID_CCDGenericPropertyPageECLSID_CCDFontPropertyPageFCLSID_CCDColorPropertyPageGCLSID_CCDLabelPropertyPageHCLSID_CCDCheckBoxPropertyPageICLSID_CCDTextBoxPropertyPageJCLSID_CCDOptionButtonPropertyPageKCLSID_CCDListBoxPropertyPageLCLSID_CCDCommandButtonPropertyPageMCLSID_CCDComboBoxPropertyPageNCLSID_CCDScrollBarPropertyPageOCLSID_CCDGroupBoxPropertyPagePCLSID_CCDXObjectPropertyPageQCLSID_CStdPropertyFrameRCLSID_CFormPropertyPageSCLSID_CGridPropertyPageTCLSID_CWSJArticlePageUCLSID_CSystemPageVCLSID_IdentityUnmarshalWCLSID_InProcFreeMarshalerXCLSID_Picture_MetafileYCLSID_Picture_EnhMetafileZCLSID_Picture_Dib[GUID_TRISTATE\IWinTypes_v0_1_c_ifspec)IWinTypes_v0_1_s_ifspec*VARENUMa{1VT_EMPTYVT_NULLVT_I2VT_I4VT_R4VT_R8VT_CYVT_DATEVT_BSTRVT_DISPATCH VT_ERROR VT_BOOL VT_VARIANT VT_UNKNOWN VT_DECIMALVT_I1VT_UI1VT_UI2VT_UI4VT_I8VT_UI8VT_INTVT_UINTVT_VOIDVT_HRESULTVT_PTRVT_SAFEARRAYVT_CARRAYVT_USERDEFINEDVT_LPSTRVT_LPWSTRVT_RECORD$VT_INT_PTR%VT_UINT_PTR&VT_FILETIME@VT_BLOBAVT_STREAMBVT_STORAGECVT_STREAMED_OBJECTDVT_STORED_OBJECTEVT_BLOB_OBJECTFVT_CFGVT_CLSIDHVT_VERSIONED_STREAMIVT_BSTR_BLOBVT_VECTORVT_ARRAY VT_BYREF@VT_RESERVEDVT_ILLEGALVT_ILLEGALMASKEDVT_TYPEMASKIID_IMallocSpyIID_IBindCtx:IID_IEnumMonikerJ IID_IRunnableObject IID_IRunningObjectTable!IID_IPersisti"IID_IPersistStream"IID_IMonikerj#IID_IROTDataX%IID_IEnumSTATSTG%IID_IStorageX&IID_IPersistFileA(IID_IPersistStorage(IID_ILockBytes)IID_IEnumFORMATETC*IID_IEnumSTATDATAl+IID_IRootStorage,IID_IAdviseSink,IID_AsyncIAdviseSinks-IID_IAdviseSink2.IID_AsyncIAdviseSink2./IID_IDataObject/IID_IDataAdviseHolder1IID_IMessageFilter1FMTID_SummaryInformation]2FMTID_DocSummaryInformation_2FMTID_UserDefinedPropertiesa2FMTID_DiscardableInformationc2FMTID_ImageSummaryInformatione2FMTID_AudioSummaryInformationg2FMTID_VideoSummaryInformationi2FMTID_MediaFileSummaryInformationk2IID_IClassActivators2IID_IFillLockBytes2IID_IProgressNotify3IID_ILayoutStorage3IID_IBlockingLock4IID_ITimeAndNoticeControl4IID_IOplockStorageN5IID_IDirectWriterLock5IID_IUrlMonM6IID_IForegroundTransfer6IID_IThumbnailExtractor7IID_IDummyHICONIncluder7IID_IProcessLock7IID_ISurrogateServiceH8IID_IInitializeSpy8IID_IApartmentShutdown9IID_IOleAdviseHolderIID_IOleCacheIID_IOleCache2IID_IOleCacheControlIID_IParseDisplayNameIID_IOleContainerpIID_IOleClientSiteIID_IOleObjectIOLETypes_v0_0_c_ifspecIOLETypes_v0_0_s_ifspecIID_IOleWindowIID_IOleLinkkIID_IOleItemContainer9IID_IOleInPlaceUIWindowIID_IOleInPlaceActiveObjectXIID_IOleInPlaceFrame IID_IOleInPlaceObject IID_IOleInPlaceSitef IID_IContinue, IID_IViewObject{ IID_IViewObject2 IID_IDropSource9 IID_IDropTarget IID_IDropSourceNotify0IID_IEnumOLEVERBIID_IServiceProviderTIOleAutomationTypes_v1_0_c_ifspecdIOleAutomationTypes_v1_0_s_ifspeceIID_ICreateTypeInfoIID_ICreateTypeInfo2 IID_ICreateTypeLibIID_ICreateTypeLib2IID_IDispatchlIID_IEnumVARIANT IID_ITypeComp IID_ITypeInfo] IID_ITypeInfo2 IID_ITypeLibIID_ITypeLib2IID_ITypeChangeEventsIID_IErrorInfolIID_ICreateErrorInfoIID_ISupportErrorInfodIID_ITypeFactoryIID_ITypeMarshalIID_IRecordInfoIID_IErrorLogIID_IPropertyBag__MIDL_itf_msxml_0000_v0_0_c_ifspec__MIDL_itf_msxml_0000_v0_0_s_ifspecLIBID_MSXMLIID_IXMLDOMImplementationIID_IXMLDOMNode(IID_IXMLDOMDocumentFragmentIID_IXMLDOMDocumentgIID_IXMLDOMNodeListvIID_IXMLDOMNamedNodeMapIID_IXMLDOMCharacterDataIID_IXMLDOMAttributeIID_IXMLDOMElementIID_IXMLDOMTextIID_IXMLDOMComment&IID_IXMLDOMProcessingInstructionIID_IXMLDOMCDATASectionIID_IXMLDOMDocumentTypeIID_IXMLDOMNotation IID_IXMLDOMEntityIID_IXMLDOMEntityReferenceIID_IXMLDOMParseErrorb IID_IXTLRuntime DIID_XMLDOMDocumentEvents> CLSID_DOMDocument] CLSID_DOMFreeThreadedDocumenta IID_IXMLHttpRequesth CLSID_XMLHTTPRequest IID_IXMLDSOControl CLSID_XMLDSOControl IID_IXMLElementCollection IID_IXMLDocumentK IID_IXMLDocument2 IID_IXMLElement% IID_IXMLElement2 IID_IXMLAttribute IID_IXMLError CLSID_XMLDocument/ CLSID_SBS_StdURLMonikerKCLSID_SBS_HttpProtocolLCLSID_SBS_FtpProtocolMCLSID_SBS_GopherProtocolNCLSID_SBS_HttpSProtocolOCLSID_SBS_FileProtocolPCLSID_SBS_MkProtocolQCLSID_SBS_UrlMkBindCtxRCLSID_SBS_SoftDistExtSCLSID_SBS_CdlProtocolTCLSID_SBS_ClassInstallFilterUCLSID_SBS_InternetSecurityManagerVCLSID_SBS_InternetZoneManagerWIID_IAsyncMoniker`CLSID_StdURLMonikeraCLSID_HttpProtocolbCLSID_FtpProtocolcCLSID_GopherProtocoldCLSID_HttpSProtocoleCLSID_FileProtocolfCLSID_MkProtocolgCLSID_StdURLProtocolhCLSID_UrlMkBindCtxiCLSID_CdlProtocoljCLSID_ClassInstallFilterkIID_IAsyncBindCtxlIID_IPersistMonikerIID_IMonikerPropIID_IBindProtocolIID_IBindinghIID_IBindStatusCallbackIID_IBindStatusCallbackExIID_IAuthenticateIID_IAuthenticateExIID_IHttpNegotiate^IID_IHttpNegotiate2IID_IHttpNegotiate3: IID_IWinInetFileStream IID_IWindowForBindingUI IID_ICodeInstallz IID_IUri IID_IUriContainer IID_IUriBuilder IID_IUriBuilderFactory^IID_IWinInetInfoIID_IHttpSecurity6IID_IWinInetHttpInfoIID_IWinInetHttpTimeoutsIID_IWinInetCacheHintsoIID_IWinInetCacheHints2SID_BindHost4IID_IBindHost>IID_IInternet`IID_IInternetBindInfoIID_IInternetBindInfoEx'IID_IInternetProtocolRootIID_IInternetProtocolIIID_IInternetProtocolExIID_IInternetProtocolSinkIID_IInternetProtocolSinkStackable1IID_IInternetSessionIID_IInternetThreadSwitch\IID_IInternetPriorityIID_IInternetProtocolInfoFCLSID_InternetSecurityManagerwCLSID_InternetZoneManagerxCLSID_PersistentZoneIdentifier{IID_IInternetSecurityMgrSiteIID_IInternetSecurityManagerIID_IInternetSecurityManagerExIID_IInternetSecurityManagerEx2IID_IZoneIdentifierIID_IInternetHostSecurityManagerGUID_CUSTOM_LOCALMACHINEZONEUNLOCKEDXIID_IInternetZoneManagerIID_IInternetZoneManagerExIID_IInternetZoneManagerEx2 CLSID_SoftDistExt!IID_ISoftDistExt!IID_ICatalogFileInfox"IID_IDataFilter"IID_IEncodingFilterFactoryp#GUID_CUSTOM_CONFIRMOBJECTSAFETY#IID_IWrappedProtocol#IID_IGetBindHandleR$IID_IBindCallbackRedirect$IID_IPropertyStorageIID_IPropertySetStorageIID_IEnumSTATPROPSTG*IID_IEnumSTATPROPSETSTGIID_StdOleGUID_DEVINTERFACE_DISK GUID_DEVINTERFACE_CDROM GUID_DEVINTERFACE_PARTITIONGUID_DEVINTERFACE_TAPEGUID_DEVINTERFACE_WRITEONCEDISKGUID_DEVINTERFACE_VOLUMEGUID_DEVINTERFACE_MEDIUMCHANGERGUID_DEVINTERFACE_FLOPPYGUID_DEVINTERFACE_CDCHANGERGUID_DEVINTERFACE_STORAGEPORTGUID_DEVINTERFACE_COMPORTGUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR_SCARD_IO_REQUESTMdwProtocol cbPciLength SCARD_IO_REQUESTzMMg_rgSCardT0Pci%.Mg_rgSCardT1Pci%=Mg_rgSCardRawPci%LMIID_IPrintDialogCallbackIID_IPrintDialogServicesfunc_ptreNN__CTOR_LIST__vN__DTOR_LIST__vNinitializedK 9 0p@__mainN@@N_@N __do_global_ctors7@jjO!nptrs9z!i:"@O#R @ __do_global_dtors@:OpO 0@eN$atexitatexitwSpGNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/natstart.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt charlong long unsigned intlong long intintptr_tC#wchar_tgshort unsigned intintlong intpthreadlocinfo(TZthreadlocaleinfostruct`M) lc_codepageQ lc_collate_cpQ lc_handlef lc_id $ lc_categoryH lc_clike) mb_cur_max)  lconv_intl_refcountK lconv_num_refcountK lconv_mon_refcountK  lconv( ctype1_refcountK0 ctype18 pctype@ pclmapH pcumapP lc_time_currXpthreadmbcinfo%" threadmbcinfostruct localeinfo_structx locinfo< mbcinfo_locale_tstruct7 tagLC_ID wLanguage wCountry wCodePageLC_ID ? locale ? wlocaleEM K wrefcount K)unsigned intQvvlong unsigned int lconv$unsigned char __lc_time_data_PHNDLRB )_XCPT_ACTIOND cXcptNumEvSigNumF )XcptActionG n_XcptActTabJc_XcptActTabCountK)_XcptActTabSizeL)_First_FPE_IndxM)_Num_FPEN)WORDDWORDvfloatQ__imp__pctype+__imp__wctype;__imp__pwctypeG\Q__newclmapP\__newcumapQ\__ptlocinfoR<__ptmbcinfoS__globallocalestatusT)__locale_changedU)__initiallocinfoV(Z__initiallocalestructinfoWx__imp___mb_cur_maxKsigned charshort intULONG_PTR1.LONG0HANDLE _LIST_ENTRYd Flinke BlinkfLIST_ENTRYg_GUID$Data1vData2Data3Data4$4GUID4IIDX4FCLSID`4WFMTIDg4jdoublelong double?_sys_errlist&_sys_nerr$)__imp___argcK__imp___argv?__imp___wargv" " E__imp__environB__imp__wenvironG __imp__pgmptrN__imp__wpgmptrS" __imp__osplatformX__imp__osver]__imp__winverb__imp__winmajorg__imp__winminorl_amblksiz 5QGUID_MAX_POWER_SAVINGSAGUID_MIN_POWER_SAVINGSAGUID_TYPICAL_POWER_SAVINGSANO_SUBGROUP_GUIDAALL_POWERSCHEMES_GUID AGUID_POWERSCHEME_PERSONALITY!AGUID_ACTIVE_POWERSCHEME"AGUID_IDLE_RESILIENCY_SUBGROUP#AGUID_IDLE_RESILIENCY_PERIOD$AGUID_DISK_COALESCING_POWERDOWN_TIMEOUT%AGUID_EXECUTION_REQUIRED_REQUEST_TIMEOUT&AGUID_VIDEO_SUBGROUP'AGUID_VIDEO_POWERDOWN_TIMEOUT(AGUID_VIDEO_ANNOYANCE_TIMEOUT)AGUID_VIDEO_ADAPTIVE_PERCENT_INCREASE*AGUID_VIDEO_DIM_TIMEOUT+AGUID_VIDEO_ADAPTIVE_POWERDOWN,AGUID_MONITOR_POWER_ON-AGUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS.AGUID_DEVICE_POWER_POLICY_VIDEO_DIM_BRIGHTNESS/AGUID_VIDEO_CURRENT_MONITOR_BRIGHTNESS0AGUID_VIDEO_ADAPTIVE_DISPLAY_BRIGHTNESS1AGUID_CONSOLE_DISPLAY_STATE2AGUID_ALLOW_DISPLAY_REQUIRED3AGUID_VIDEO_CONSOLE_LOCK_TIMEOUT4AGUID_ADAPTIVE_POWER_BEHAVIOR_SUBGROUP5AGUID_NON_ADAPTIVE_INPUT_TIMEOUT6AGUID_DISK_SUBGROUP7AGUID_DISK_POWERDOWN_TIMEOUT8AGUID_DISK_IDLE_TIMEOUT9AGUID_DISK_BURST_IGNORE_THRESHOLD:AGUID_DISK_ADAPTIVE_POWERDOWN;AGUID_SLEEP_SUBGROUP<AGUID_SLEEP_IDLE_THRESHOLD=AGUID_STANDBY_TIMEOUT>AGUID_UNATTEND_SLEEP_TIMEOUT?AGUID_HIBERNATE_TIMEOUT@AGUID_HIBERNATE_FASTS4_POLICYAAGUID_CRITICAL_POWER_TRANSITIONBAGUID_SYSTEM_AWAYMODECAGUID_ALLOW_AWAYMODEDAGUID_ALLOW_STANDBY_STATESEAGUID_ALLOW_RTC_WAKEFAGUID_ALLOW_SYSTEM_REQUIREDGAGUID_SYSTEM_BUTTON_SUBGROUPHAGUID_POWERBUTTON_ACTIONIAGUID_SLEEPBUTTON_ACTIONJAGUID_USERINTERFACEBUTTON_ACTIONKAGUID_LIDCLOSE_ACTIONLAGUID_LIDOPEN_POWERSTATEMAGUID_BATTERY_SUBGROUPNAGUID_BATTERY_DISCHARGE_ACTION_0OAGUID_BATTERY_DISCHARGE_LEVEL_0PAGUID_BATTERY_DISCHARGE_FLAGS_0QAGUID_BATTERY_DISCHARGE_ACTION_1RAGUID_BATTERY_DISCHARGE_LEVEL_1SAGUID_BATTERY_DISCHARGE_FLAGS_1TAGUID_BATTERY_DISCHARGE_ACTION_2UAGUID_BATTERY_DISCHARGE_LEVEL_2VAGUID_BATTERY_DISCHARGE_FLAGS_2WAGUID_BATTERY_DISCHARGE_ACTION_3XAGUID_BATTERY_DISCHARGE_LEVEL_3YAGUID_BATTERY_DISCHARGE_FLAGS_3ZAGUID_PROCESSOR_SETTINGS_SUBGROUP[AGUID_PROCESSOR_THROTTLE_POLICY\AGUID_PROCESSOR_THROTTLE_MAXIMUM]AGUID_PROCESSOR_THROTTLE_MINIMUM^AGUID_PROCESSOR_ALLOW_THROTTLING_AGUID_PROCESSOR_IDLESTATE_POLICY`AGUID_PROCESSOR_PERFSTATE_POLICYaAGUID_PROCESSOR_PERF_INCREASE_THRESHOLDbAGUID_PROCESSOR_PERF_DECREASE_THRESHOLDcAGUID_PROCESSOR_PERF_INCREASE_POLICYdAGUID_PROCESSOR_PERF_DECREASE_POLICYeAGUID_PROCESSOR_PERF_INCREASE_TIMEfAGUID_PROCESSOR_PERF_DECREASE_TIMEgAGUID_PROCESSOR_PERF_TIME_CHECKhAGUID_PROCESSOR_PERF_BOOST_POLICYiAGUID_PROCESSOR_PERF_BOOST_MODEjAGUID_PROCESSOR_IDLE_ALLOW_SCALINGkAGUID_PROCESSOR_IDLE_DISABLElAGUID_PROCESSOR_IDLE_STATE_MAXIMUMmAGUID_PROCESSOR_IDLE_TIME_CHECKnAGUID_PROCESSOR_IDLE_DEMOTE_THRESHOLDoAGUID_PROCESSOR_IDLE_PROMOTE_THRESHOLDpAGUID_PROCESSOR_CORE_PARKING_INCREASE_THRESHOLDqAGUID_PROCESSOR_CORE_PARKING_DECREASE_THRESHOLDrAGUID_PROCESSOR_CORE_PARKING_INCREASE_POLICYsAGUID_PROCESSOR_CORE_PARKING_DECREASE_POLICYtAGUID_PROCESSOR_CORE_PARKING_MAX_CORESuAGUID_PROCESSOR_CORE_PARKING_MIN_CORESvAGUID_PROCESSOR_CORE_PARKING_INCREASE_TIMEwAGUID_PROCESSOR_CORE_PARKING_DECREASE_TIMExAGUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_DECREASE_FACTORyAGUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_THRESHOLDzAGUID_PROCESSOR_CORE_PARKING_AFFINITY_WEIGHTING{AGUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_DECREASE_FACTOR|AGUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_THRESHOLD}AGUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_WEIGHTING~AGUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_THRESHOLDAGUID_PROCESSOR_PARKING_CORE_OVERRIDEAGUID_PROCESSOR_PARKING_PERF_STATEAGUID_PROCESSOR_PARKING_CONCURRENCY_THRESHOLDAGUID_PROCESSOR_PARKING_HEADROOM_THRESHOLDAGUID_PROCESSOR_PERF_HISTORYAGUID_PROCESSOR_PERF_LATENCY_HINTAGUID_PROCESSOR_DISTRIBUTE_UTILITYAGUID_SYSTEM_COOLING_POLICYAGUID_LOCK_CONSOLE_ON_WAKEAGUID_DEVICE_IDLE_POLICYAGUID_ACDC_POWER_SOURCEAGUID_LIDSWITCH_STATE_CHANGEAGUID_BATTERY_PERCENTAGE_REMAININGAGUID_GLOBAL_USER_PRESENCEAGUID_SESSION_DISPLAY_STATUSAGUID_SESSION_USER_PRESENCEAGUID_IDLE_BACKGROUND_TASKAGUID_BACKGROUND_TASK_NOTIFICATIONAGUID_APPLAUNCH_BUTTONAGUID_PCIEXPRESS_SETTINGS_SUBGROUPAGUID_PCIEXPRESS_ASPM_POLICYAGUID_ENABLE_SWITCH_FORCED_SHUTDOWNAPPM_PERFSTATE_CHANGE_GUIDAPPM_PERFSTATE_DOMAIN_CHANGE_GUIDAPPM_IDLESTATE_CHANGE_GUIDAPPM_PERFSTATES_DATA_GUIDAPPM_IDLESTATES_DATA_GUIDAPPM_IDLE_ACCOUNTING_GUIDAPPM_IDLE_ACCOUNTING_EX_GUIDAPPM_THERMALCONSTRAINT_GUIDAPPM_PERFMON_PERFSTATE_GUIDAPPM_THERMAL_POLICY_CHANGE_GUIDA _RTL_CRITICAL_SECTION_DEBUG059 Type6  CreatorBackTraceIndex7  CriticalSection8%  ProcessLocksList9 EntryCount:  ContentionCount; $ Flags< ( CreatorBackTraceIndexHigh= , SpareWORD> . _RTL_CRITICAL_SECTION(P DebugInfoQ# LockCountR i RecursionCountS i OwningThreadTw LockSemaphoreUw SpinCountVW 9 PRTL_CRITICAL_SECTION_DEBUG?# !7RTL_CRITICAL_SECTIONW9 CRITICAL_SECTION !VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN AVIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT ARPC_IF_HANDLE BtagCOINITBASEQ!COINITBASE_MULTITHREADEDIWinTypesBase_v0_1_c_ifspec *!IWinTypesBase_v0_1_s_ifspec +!IID_IUnknownaAIID_AsyncIUnknownAIID_IClassFactory8AIID_IMarshalAIID_INoMarshalAIID_IAgileObjectAIID_IAgileReference>AIID_IMarshal2AIID_IMallocAIID_IStdMarshalInfoAIID_IExternalConnectionAIID_IMultiQIbAIID_AsyncIMultiQIAIID_IInternalUnknownAIID_IEnumUnknownbAIID_IEnumStringAIID_ISequentialStreampAIID_IStreamAIID_IRpcChannelBuffer% AIID_IRpcChannelBuffer2 AIID_IAsyncRpcChannelBuffer! AIID_IRpcChannelBuffer3 AIID_IRpcSyntaxNegotiate AIID_IRpcProxyBuffer AIID_IRpcStubBufferI AIID_IPSFactoryBuffer AIID_IChannelHookH AIID_IClientSecurity(AIID_IServerSecurityAIID_IRpcOptions0AIID_IGlobalOptionsAIID_ISurrogateAIID_IGlobalInterfaceTabletAIID_ISynchronizeAIID_ISynchronizeHandleFAIID_ISynchronizeEventAIID_ISynchronizeContainerAIID_ISynchronizeMutexJAIID_ICancelMethodCallsAIID_IAsyncManagerAIID_ICallFactorywAIID_IRpcHelperAIID_IReleaseMarshalBuffers&AIID_IWaitMultiplexAIID_IAddrTrackingControlAIID_IAddrExclusionControl,AIID_IPipeByteAIID_IPipeLongAIID_IPipeDoubleEAIID_IComThreadingInfoAIID_IProcessInitControl1AIID_IFastRundownAIID_IMarshalingStreamAIID_ICallbackWithNoReentrancyToApplicationSTAzAGUID_NULL RCATID_MARSHALERRIID_IRpcChannelRIID_IRpcStubRIID_IStubManagerRIID_IRpcProxyRIID_IProxyManagerRIID_IPSFactoryRIID_IInternalMonikerRIID_IDfReserved1RIID_IDfReserved2RIID_IDfReserved3RCLSID_StdMarshaleCLSID_AggStdMarshaleCLSID_StdAsyncActManagereIID_IStubRIID_IProxyRIID_IEnumGenericRIID_IEnumHolderRIID_IEnumCallback RIID_IOleManager!RIID_IOlePresObj"RIID_IDebug#RIID_IDebugStream$RCLSID_PSGenObject%eCLSID_PSClientSite&eCLSID_PSClassObject'eCLSID_PSInPlaceActive(eCLSID_PSInPlaceFrame)eCLSID_PSDragDrop*eCLSID_PSBindCtx+eCLSID_PSEnumerators,eCLSID_StaticMetafile-eCLSID_StaticDib.eCID_CDfsVolume/eCLSID_DCOMAccessControl0eCLSID_GlobalOptions1eCLSID_StdGlobalInterfaceTable2eCLSID_ComBinding3eCLSID_StdEvent4eCLSID_ManualResetEvent5eCLSID_SynchronizeContainer6eCLSID_AddrControl7eCLSID_CCDFormKrnl8eCLSID_CCDPropertyPage9eCLSID_CCDFormDialog:eCLSID_CCDCommandButton;eCLSID_CCDComboBox<eCLSID_CCDTextBox=eCLSID_CCDCheckBox>eCLSID_CCDLabel?eCLSID_CCDOptionButton@eCLSID_CCDListBoxAeCLSID_CCDScrollBarBeCLSID_CCDGroupBoxCeCLSID_CCDGeneralPropertyPageDeCLSID_CCDGenericPropertyPageEeCLSID_CCDFontPropertyPageFeCLSID_CCDColorPropertyPageGeCLSID_CCDLabelPropertyPageHeCLSID_CCDCheckBoxPropertyPageIeCLSID_CCDTextBoxPropertyPageJeCLSID_CCDOptionButtonPropertyPageKeCLSID_CCDListBoxPropertyPageLeCLSID_CCDCommandButtonPropertyPageMeCLSID_CCDComboBoxPropertyPageNeCLSID_CCDScrollBarPropertyPageOeCLSID_CCDGroupBoxPropertyPagePeCLSID_CCDXObjectPropertyPageQeCLSID_CStdPropertyFrameReCLSID_CFormPropertyPageSeCLSID_CGridPropertyPageTeCLSID_CWSJArticlePageUeCLSID_CSystemPageVeCLSID_IdentityUnmarshalWeCLSID_InProcFreeMarshalerXeCLSID_Picture_MetafileYeCLSID_Picture_EnhMetafileZeCLSID_Picture_Dib[eGUID_TRISTATE\AIWinTypes_v0_1_c_ifspec)!IWinTypes_v0_1_s_ifspec*!VARENUMQ4VT_EMPTYVT_NULLVT_I2VT_I4VT_R4VT_R8VT_CYVT_DATEVT_BSTRVT_DISPATCH VT_ERROR VT_BOOL VT_VARIANT VT_UNKNOWN VT_DECIMALVT_I1VT_UI1VT_UI2VT_UI4VT_I8VT_UI8VT_INTVT_UINTVT_VOIDVT_HRESULTVT_PTRVT_SAFEARRAYVT_CARRAYVT_USERDEFINEDVT_LPSTRVT_LPWSTRVT_RECORD$VT_INT_PTR%VT_UINT_PTR&VT_FILETIME@VT_BLOBAVT_STREAMBVT_STORAGECVT_STREAMED_OBJECTDVT_STORED_OBJECTEVT_BLOB_OBJECTFVT_CFGVT_CLSIDHVT_VERSIONED_STREAMIVT_BSTR_BLOBVT_VECTORVT_ARRAY VT_BYREF@VT_RESERVEDVT_ILLEGALVT_ILLEGALMASKEDVT_TYPEMASKIID_IMallocSpyAIID_IBindCtx:AIID_IEnumMonikerJ AIID_IRunnableObject AIID_IRunningObjectTable!AIID_IPersisti"AIID_IPersistStream"AIID_IMonikerj#AIID_IROTDataX%AIID_IEnumSTATSTG%AIID_IStorageX&AIID_IPersistFileA(AIID_IPersistStorage(AIID_ILockBytes)AIID_IEnumFORMATETC*AIID_IEnumSTATDATAl+AIID_IRootStorage,AIID_IAdviseSink,AIID_AsyncIAdviseSinks-AIID_IAdviseSink2.AIID_AsyncIAdviseSink2./AIID_IDataObject/AIID_IDataAdviseHolder1AIID_IMessageFilter1AFMTID_SummaryInformation]2xFMTID_DocSummaryInformation_2xFMTID_UserDefinedPropertiesa2xFMTID_DiscardableInformationc2xFMTID_ImageSummaryInformatione2xFMTID_AudioSummaryInformationg2xFMTID_VideoSummaryInformationi2xFMTID_MediaFileSummaryInformationk2xIID_IClassActivators2AIID_IFillLockBytes2AIID_IProgressNotify3AIID_ILayoutStorage3AIID_IBlockingLock4AIID_ITimeAndNoticeControl4AIID_IOplockStorageN5AIID_IDirectWriterLock5AIID_IUrlMonM6AIID_IForegroundTransfer6AIID_IThumbnailExtractor7AIID_IDummyHICONIncluder7AIID_IProcessLock7AIID_ISurrogateServiceH8AIID_IInitializeSpy8AIID_IApartmentShutdown9AIID_IOleAdviseHolderAIID_IOleCacheAIID_IOleCache2AIID_IOleCacheControlAIID_IParseDisplayNameAIID_IOleContainerpAIID_IOleClientSiteAIID_IOleObjectAIOLETypes_v0_0_c_ifspec!IOLETypes_v0_0_s_ifspec!IID_IOleWindowAIID_IOleLinkkAIID_IOleItemContainer9AIID_IOleInPlaceUIWindowAIID_IOleInPlaceActiveObjectXAIID_IOleInPlaceFrame AIID_IOleInPlaceObject AIID_IOleInPlaceSitef AIID_IContinue, AIID_IViewObject{ AIID_IViewObject2 AIID_IDropSource9 AIID_IDropTarget AIID_IDropSourceNotify0AIID_IEnumOLEVERBAIID_IServiceProviderTAIOleAutomationTypes_v1_0_c_ifspecd!IOleAutomationTypes_v1_0_s_ifspece!IID_ICreateTypeInfoAIID_ICreateTypeInfo2 AIID_ICreateTypeLibAIID_ICreateTypeLib2AIID_IDispatchlAIID_IEnumVARIANT AIID_ITypeComp AIID_ITypeInfo] AIID_ITypeInfo2 AIID_ITypeLibAIID_ITypeLib2AIID_ITypeChangeEventsAIID_IErrorInfolAIID_ICreateErrorInfoAIID_ISupportErrorInfodAIID_ITypeFactoryAIID_ITypeMarshalAIID_IRecordInfoAIID_IErrorLogAIID_IPropertyBagA__MIDL_itf_msxml_0000_v0_0_c_ifspec!__MIDL_itf_msxml_0000_v0_0_s_ifspec!LIBID_MSXMLRIID_IXMLDOMImplementationRIID_IXMLDOMNode(RIID_IXMLDOMDocumentFragmentRIID_IXMLDOMDocumentgRIID_IXMLDOMNodeListvRIID_IXMLDOMNamedNodeMapRIID_IXMLDOMCharacterDataRIID_IXMLDOMAttributeRIID_IXMLDOMElementRIID_IXMLDOMTextRIID_IXMLDOMComment&RIID_IXMLDOMProcessingInstructionRIID_IXMLDOMCDATASectionRIID_IXMLDOMDocumentTypeRIID_IXMLDOMNotation RIID_IXMLDOMEntityRIID_IXMLDOMEntityReferenceRIID_IXMLDOMParseErrorb RIID_IXTLRuntime RDIID_XMLDOMDocumentEvents> RCLSID_DOMDocument] eCLSID_DOMFreeThreadedDocumenta eIID_IXMLHttpRequesth RCLSID_XMLHTTPRequest eIID_IXMLDSOControl RCLSID_XMLDSOControl eIID_IXMLElementCollection RIID_IXMLDocumentK RIID_IXMLDocument2 RIID_IXMLElement% RIID_IXMLElement2 RIID_IXMLAttribute RIID_IXMLError RCLSID_XMLDocument/ eCLSID_SBS_StdURLMonikerKRCLSID_SBS_HttpProtocolLRCLSID_SBS_FtpProtocolMRCLSID_SBS_GopherProtocolNRCLSID_SBS_HttpSProtocolORCLSID_SBS_FileProtocolPRCLSID_SBS_MkProtocolQRCLSID_SBS_UrlMkBindCtxRRCLSID_SBS_SoftDistExtSRCLSID_SBS_CdlProtocolTRCLSID_SBS_ClassInstallFilterURCLSID_SBS_InternetSecurityManagerVRCLSID_SBS_InternetZoneManagerWRIID_IAsyncMoniker`RCLSID_StdURLMonikeraRCLSID_HttpProtocolbRCLSID_FtpProtocolcRCLSID_GopherProtocoldRCLSID_HttpSProtocoleRCLSID_FileProtocolfRCLSID_MkProtocolgRCLSID_StdURLProtocolhRCLSID_UrlMkBindCtxiRCLSID_CdlProtocoljRCLSID_ClassInstallFilterkRIID_IAsyncBindCtxlRIID_IPersistMonikerAIID_IMonikerPropAIID_IBindProtocolAIID_IBindinghAIID_IBindStatusCallbackAIID_IBindStatusCallbackExAIID_IAuthenticateAIID_IAuthenticateExAIID_IHttpNegotiate^AIID_IHttpNegotiate2AIID_IHttpNegotiate3: AIID_IWinInetFileStream AIID_IWindowForBindingUI AIID_ICodeInstallz AIID_IUri AIID_IUriContainer AIID_IUriBuilder AIID_IUriBuilderFactory^AIID_IWinInetInfoAIID_IHttpSecurity6AIID_IWinInetHttpInfoAIID_IWinInetHttpTimeoutsAIID_IWinInetCacheHintsoAIID_IWinInetCacheHints2ASID_BindHost4AIID_IBindHost>AIID_IInternet`AIID_IInternetBindInfoAIID_IInternetBindInfoEx'AIID_IInternetProtocolRootAIID_IInternetProtocolIAIID_IInternetProtocolExAIID_IInternetProtocolSinkAIID_IInternetProtocolSinkStackable1AIID_IInternetSessionAIID_IInternetThreadSwitch\AIID_IInternetPriorityAIID_IInternetProtocolInfoFACLSID_InternetSecurityManagerwRCLSID_InternetZoneManagerxRCLSID_PersistentZoneIdentifier{RIID_IInternetSecurityMgrSiteAIID_IInternetSecurityManagerAIID_IInternetSecurityManagerExAIID_IInternetSecurityManagerEx2AIID_IZoneIdentifierAIID_IInternetHostSecurityManagerAGUID_CUSTOM_LOCALMACHINEZONEUNLOCKEDXAIID_IInternetZoneManagerAIID_IInternetZoneManagerExAIID_IInternetZoneManagerEx2 ACLSID_SoftDistExt!RIID_ISoftDistExt!AIID_ICatalogFileInfox"AIID_IDataFilter"AIID_IEncodingFilterFactoryp#AGUID_CUSTOM_CONFIRMOBJECTSAFETY#AIID_IWrappedProtocol#AIID_IGetBindHandleR$AIID_IBindCallbackRedirect$AIID_IPropertyStorageAIID_IPropertySetStorageAIID_IEnumSTATPROPSTG*AIID_IEnumSTATPROPSETSTGAIID_StdOleRGUID_DEVINTERFACE_DISK AGUID_DEVINTERFACE_CDROM AGUID_DEVINTERFACE_PARTITIONAGUID_DEVINTERFACE_TAPEAGUID_DEVINTERFACE_WRITEONCEDISKAGUID_DEVINTERFACE_VOLUMEAGUID_DEVINTERFACE_MEDIUMCHANGERAGUID_DEVINTERFACE_FLOPPYAGUID_DEVINTERFACE_CDCHANGERAGUID_DEVINTERFACE_STORAGEPORTAGUID_DEVINTERFACE_COMPORTAGUID_DEVINTERFACE_SERENUM_BUS_ENUMERATORA_SCARD_IO_REQUESTJPdwProtocol cbPciLength SCARD_IO_REQUESTPJPg_rgSCardT0Pci%.cPg_rgSCardT1Pci%=cPg_rgSCardRawPci%LcPIID_IPrintDialogCallbackAIID_IPrintDialogServicesA_commode$)@% Qosfhnd&osfile' pipech( lockinitflag) ) lock*-!textmode+ 8unicode, 8pipech2- Q9Qioinfo.QQQQQ__imp___badioinfoDQ__imp___pioinfoIQ_dowildcardf)_newmodeg)__imp___winitenvj __imp___initenvo5QR__uninitialized__initializing__initialized 5WRR__native_startup_state+R__native_startup_lockRR!__native_dllmain_reason a__native_vcclrit_reason a"R  $0@"S   0@"R " py@"R  xy@= GNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/wildcard.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt _dowildcard  @p@intk GNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/charmax.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt`@ charlong long unsigned intlong long intshort unsigned intintlong intunsigned intlong unsigned intunsigned char_PIFViomingw_initcharmax  Pp@_charmax 00@__mingw_pinit[ (@my_lconv_init `@ g@  VV P GNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/dllargv.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crtp@ charlong long unsigned intlong long intintptr_tC#wchar_tgshort unsigned intintlong intpthreadlocinfo(cithreadlocaleinfostruct`{8 lc_codepage` lc_collate_cp` lc_handleu lc_id $ lc_categoryH lc_clike8 mb_cur_max8  lconv_intl_refcountZ lconv_num_refcountZ lconv_mon_refcountZ  lconv( ctype1_refcountZ0 ctype18 pctype@ pclmapH pcumapP lc_time_currXpthreadmbcinfo%+1 threadmbcinfostruct localeinfo_struct locinfoK mbcinfo_locale_tstructF tagLC_ID wLanguage wCountry wCodePageLC_ID N locale N wlocaleT{ Z wrefcount Z 8unsigned int`long unsigned int lconv3unsigned char __lc_time_data_PHNDLRB&8_XCPT_ACTIOND rXcptNumESigNumF 8XcptActionG &}_XcptActTabJr_XcptActTabCountK8_XcptActTabSizeL8_First_FPE_IndxM8_Num_FPEN8WORDDWORDfloat`__imp__pctype+-__imp__wctype;-__imp__pwctypeG-k`__newclmapPk__newcumapQk__ptlocinfoRK__ptmbcinfoS__globallocalestatusT8__locale_changedU8__initiallocinfoV(i__initiallocalestructinfoW__imp___mb_cur_maxZsigned charshort intULONG_PTR1.LONG?HANDLE _LIST_ENTRYd Flinke BlinkfLIST_ENTRYg_GUID3Data1Data2Data3Data43CGUIDCIIDXCUCLSID`CfFMTIDgCydoublelong doubleN_sys_errlist &_sys_nerr $8__imp___argc Z__imp___argv   N__imp___wargv "+ 1 T__imp__environ B __imp__wenviron G+ __imp__pgmptr N __imp__wpgmptr S1 __imp__osplatform X__imp__osver ]__imp__winver b__imp__winmajor g__imp__winminor l_amblksiz 5`GUID_MAX_POWER_SAVINGSPGUID_MIN_POWER_SAVINGSPGUID_TYPICAL_POWER_SAVINGSPNO_SUBGROUP_GUIDPALL_POWERSCHEMES_GUID PGUID_POWERSCHEME_PERSONALITY!PGUID_ACTIVE_POWERSCHEME"PGUID_IDLE_RESILIENCY_SUBGROUP#PGUID_IDLE_RESILIENCY_PERIOD$PGUID_DISK_COALESCING_POWERDOWN_TIMEOUT%PGUID_EXECUTION_REQUIRED_REQUEST_TIMEOUT&PGUID_VIDEO_SUBGROUP'PGUID_VIDEO_POWERDOWN_TIMEOUT(PGUID_VIDEO_ANNOYANCE_TIMEOUT)PGUID_VIDEO_ADAPTIVE_PERCENT_INCREASE*PGUID_VIDEO_DIM_TIMEOUT+PGUID_VIDEO_ADAPTIVE_POWERDOWN,PGUID_MONITOR_POWER_ON-PGUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS.PGUID_DEVICE_POWER_POLICY_VIDEO_DIM_BRIGHTNESS/PGUID_VIDEO_CURRENT_MONITOR_BRIGHTNESS0PGUID_VIDEO_ADAPTIVE_DISPLAY_BRIGHTNESS1PGUID_CONSOLE_DISPLAY_STATE2PGUID_ALLOW_DISPLAY_REQUIRED3PGUID_VIDEO_CONSOLE_LOCK_TIMEOUT4PGUID_ADAPTIVE_POWER_BEHAVIOR_SUBGROUP5PGUID_NON_ADAPTIVE_INPUT_TIMEOUT6PGUID_DISK_SUBGROUP7PGUID_DISK_POWERDOWN_TIMEOUT8PGUID_DISK_IDLE_TIMEOUT9PGUID_DISK_BURST_IGNORE_THRESHOLD:PGUID_DISK_ADAPTIVE_POWERDOWN;PGUID_SLEEP_SUBGROUP<PGUID_SLEEP_IDLE_THRESHOLD=PGUID_STANDBY_TIMEOUT>PGUID_UNATTEND_SLEEP_TIMEOUT?PGUID_HIBERNATE_TIMEOUT@PGUID_HIBERNATE_FASTS4_POLICYAPGUID_CRITICAL_POWER_TRANSITIONBPGUID_SYSTEM_AWAYMODECPGUID_ALLOW_AWAYMODEDPGUID_ALLOW_STANDBY_STATESEPGUID_ALLOW_RTC_WAKEFPGUID_ALLOW_SYSTEM_REQUIREDGPGUID_SYSTEM_BUTTON_SUBGROUPHPGUID_POWERBUTTON_ACTIONIPGUID_SLEEPBUTTON_ACTIONJPGUID_USERINTERFACEBUTTON_ACTIONKPGUID_LIDCLOSE_ACTIONLPGUID_LIDOPEN_POWERSTATEMPGUID_BATTERY_SUBGROUPNPGUID_BATTERY_DISCHARGE_ACTION_0OPGUID_BATTERY_DISCHARGE_LEVEL_0PPGUID_BATTERY_DISCHARGE_FLAGS_0QPGUID_BATTERY_DISCHARGE_ACTION_1RPGUID_BATTERY_DISCHARGE_LEVEL_1SPGUID_BATTERY_DISCHARGE_FLAGS_1TPGUID_BATTERY_DISCHARGE_ACTION_2UPGUID_BATTERY_DISCHARGE_LEVEL_2VPGUID_BATTERY_DISCHARGE_FLAGS_2WPGUID_BATTERY_DISCHARGE_ACTION_3XPGUID_BATTERY_DISCHARGE_LEVEL_3YPGUID_BATTERY_DISCHARGE_FLAGS_3ZPGUID_PROCESSOR_SETTINGS_SUBGROUP[PGUID_PROCESSOR_THROTTLE_POLICY\PGUID_PROCESSOR_THROTTLE_MAXIMUM]PGUID_PROCESSOR_THROTTLE_MINIMUM^PGUID_PROCESSOR_ALLOW_THROTTLING_PGUID_PROCESSOR_IDLESTATE_POLICY`PGUID_PROCESSOR_PERFSTATE_POLICYaPGUID_PROCESSOR_PERF_INCREASE_THRESHOLDbPGUID_PROCESSOR_PERF_DECREASE_THRESHOLDcPGUID_PROCESSOR_PERF_INCREASE_POLICYdPGUID_PROCESSOR_PERF_DECREASE_POLICYePGUID_PROCESSOR_PERF_INCREASE_TIMEfPGUID_PROCESSOR_PERF_DECREASE_TIMEgPGUID_PROCESSOR_PERF_TIME_CHECKhPGUID_PROCESSOR_PERF_BOOST_POLICYiPGUID_PROCESSOR_PERF_BOOST_MODEjPGUID_PROCESSOR_IDLE_ALLOW_SCALINGkPGUID_PROCESSOR_IDLE_DISABLElPGUID_PROCESSOR_IDLE_STATE_MAXIMUMmPGUID_PROCESSOR_IDLE_TIME_CHECKnPGUID_PROCESSOR_IDLE_DEMOTE_THRESHOLDoPGUID_PROCESSOR_IDLE_PROMOTE_THRESHOLDpPGUID_PROCESSOR_CORE_PARKING_INCREASE_THRESHOLDqPGUID_PROCESSOR_CORE_PARKING_DECREASE_THRESHOLDrPGUID_PROCESSOR_CORE_PARKING_INCREASE_POLICYsPGUID_PROCESSOR_CORE_PARKING_DECREASE_POLICYtPGUID_PROCESSOR_CORE_PARKING_MAX_CORESuPGUID_PROCESSOR_CORE_PARKING_MIN_CORESvPGUID_PROCESSOR_CORE_PARKING_INCREASE_TIMEwPGUID_PROCESSOR_CORE_PARKING_DECREASE_TIMExPGUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_DECREASE_FACTORyPGUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_THRESHOLDzPGUID_PROCESSOR_CORE_PARKING_AFFINITY_WEIGHTING{PGUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_DECREASE_FACTOR|PGUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_THRESHOLD}PGUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_WEIGHTING~PGUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_THRESHOLDPGUID_PROCESSOR_PARKING_CORE_OVERRIDEPGUID_PROCESSOR_PARKING_PERF_STATEPGUID_PROCESSOR_PARKING_CONCURRENCY_THRESHOLDPGUID_PROCESSOR_PARKING_HEADROOM_THRESHOLDPGUID_PROCESSOR_PERF_HISTORYPGUID_PROCESSOR_PERF_LATENCY_HINTPGUID_PROCESSOR_DISTRIBUTE_UTILITYPGUID_SYSTEM_COOLING_POLICYPGUID_LOCK_CONSOLE_ON_WAKEPGUID_DEVICE_IDLE_POLICYPGUID_ACDC_POWER_SOURCEPGUID_LIDSWITCH_STATE_CHANGEPGUID_BATTERY_PERCENTAGE_REMAININGPGUID_GLOBAL_USER_PRESENCEPGUID_SESSION_DISPLAY_STATUSPGUID_SESSION_USER_PRESENCEPGUID_IDLE_BACKGROUND_TASKPGUID_BACKGROUND_TASK_NOTIFICATIONPGUID_APPLAUNCH_BUTTONPGUID_PCIEXPRESS_SETTINGS_SUBGROUPPGUID_PCIEXPRESS_ASPM_POLICYPGUID_ENABLE_SWITCH_FORCED_SHUTDOWNPPPM_PERFSTATE_CHANGE_GUIDPPPM_PERFSTATE_DOMAIN_CHANGE_GUIDPPPM_IDLESTATE_CHANGE_GUIDPPPM_PERFSTATES_DATA_GUIDPPPM_IDLESTATES_DATA_GUIDPPPM_IDLE_ACCOUNTING_GUIDPPPM_IDLE_ACCOUNTING_EX_GUIDPPPM_THERMALCONSTRAINT_GUIDPPPM_PERFMON_PERFSTATE_GUIDPPPM_THERMAL_POLICY_CHANGE_GUIDP _RTL_CRITICAL_SECTION_DEBUG05H Type6  CreatorBackTraceIndex7  CriticalSection8%  ProcessLocksList9 EntryCount:  ContentionCount; $ Flags< ( CreatorBackTraceIndexHigh= , SpareWORD> . _RTL_CRITICAL_SECTION(P DebugInfoQ# LockCountR x RecursionCountS x OwningThreadT LockSemaphoreU SpinCountVf H PRTL_CRITICAL_SECTION_DEBUG?#!FRTL_CRITICAL_SECTIONWH CRITICAL_SECTION !VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN PVIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT PRPC_IF_HANDLE BIWinTypesBase_v0_1_c_ifspec*!IWinTypesBase_v0_1_s_ifspec+!IID_IUnknownaPIID_AsyncIUnknownPIID_IClassFactory8PIID_IMarshalPIID_INoMarshalPIID_IAgileObjectPIID_IAgileReference>PIID_IMarshal2PIID_IMallocPIID_IStdMarshalInfoPIID_IExternalConnectionPIID_IMultiQIbPIID_AsyncIMultiQIPIID_IInternalUnknownPIID_IEnumUnknownbPIID_IEnumStringPIID_ISequentialStreampPIID_IStreamPIID_IRpcChannelBuffer% PIID_IRpcChannelBuffer2 PIID_IAsyncRpcChannelBuffer! PIID_IRpcChannelBuffer3 PIID_IRpcSyntaxNegotiate PIID_IRpcProxyBuffer PIID_IRpcStubBufferI PIID_IPSFactoryBuffer PIID_IChannelHookH PIID_IClientSecurity(PIID_IServerSecurityPIID_IRpcOptions0PIID_IGlobalOptionsPIID_ISurrogatePIID_IGlobalInterfaceTabletPIID_ISynchronizePIID_ISynchronizeHandleFPIID_ISynchronizeEventPIID_ISynchronizeContainerPIID_ISynchronizeMutexJPIID_ICancelMethodCallsPIID_IAsyncManagerPIID_ICallFactorywPIID_IRpcHelperPIID_IReleaseMarshalBuffers&PIID_IWaitMultiplexPIID_IAddrTrackingControlPIID_IAddrExclusionControl,PIID_IPipeBytePIID_IPipeLongPIID_IPipeDoubleEPIID_IComThreadingInfoPIID_IProcessInitControl1PIID_IFastRundownPIID_IMarshalingStreamPIID_ICallbackWithNoReentrancyToApplicationSTAzPGUID_NULL aCATID_MARSHALERaIID_IRpcChannelaIID_IRpcStubaIID_IStubManageraIID_IRpcProxyaIID_IProxyManageraIID_IPSFactoryaIID_IInternalMonikeraIID_IDfReserved1aIID_IDfReserved2aIID_IDfReserved3aCLSID_StdMarshaltCLSID_AggStdMarshaltCLSID_StdAsyncActManagertIID_IStubaIID_IProxyaIID_IEnumGenericaIID_IEnumHolderaIID_IEnumCallback aIID_IOleManager!aIID_IOlePresObj"aIID_IDebug#aIID_IDebugStream$aCLSID_PSGenObject%tCLSID_PSClientSite&tCLSID_PSClassObject'tCLSID_PSInPlaceActive(tCLSID_PSInPlaceFrame)tCLSID_PSDragDrop*tCLSID_PSBindCtx+tCLSID_PSEnumerators,tCLSID_StaticMetafile-tCLSID_StaticDib.tCID_CDfsVolume/tCLSID_DCOMAccessControl0tCLSID_GlobalOptions1tCLSID_StdGlobalInterfaceTable2tCLSID_ComBinding3tCLSID_StdEvent4tCLSID_ManualResetEvent5tCLSID_SynchronizeContainer6tCLSID_AddrControl7tCLSID_CCDFormKrnl8tCLSID_CCDPropertyPage9tCLSID_CCDFormDialog:tCLSID_CCDCommandButton;tCLSID_CCDComboBox<tCLSID_CCDTextBox=tCLSID_CCDCheckBox>tCLSID_CCDLabel?tCLSID_CCDOptionButton@tCLSID_CCDListBoxAtCLSID_CCDScrollBarBtCLSID_CCDGroupBoxCtCLSID_CCDGeneralPropertyPageDtCLSID_CCDGenericPropertyPageEtCLSID_CCDFontPropertyPageFtCLSID_CCDColorPropertyPageGtCLSID_CCDLabelPropertyPageHtCLSID_CCDCheckBoxPropertyPageItCLSID_CCDTextBoxPropertyPageJtCLSID_CCDOptionButtonPropertyPageKtCLSID_CCDListBoxPropertyPageLtCLSID_CCDCommandButtonPropertyPageMtCLSID_CCDComboBoxPropertyPageNtCLSID_CCDScrollBarPropertyPageOtCLSID_CCDGroupBoxPropertyPagePtCLSID_CCDXObjectPropertyPageQtCLSID_CStdPropertyFrameRtCLSID_CFormPropertyPageStCLSID_CGridPropertyPageTtCLSID_CWSJArticlePageUtCLSID_CSystemPageVtCLSID_IdentityUnmarshalWtCLSID_InProcFreeMarshalerXtCLSID_Picture_MetafileYtCLSID_Picture_EnhMetafileZtCLSID_Picture_Dib[tGUID_TRISTATE\PIWinTypes_v0_1_c_ifspec)!IWinTypes_v0_1_s_ifspec*!IID_IMallocSpyPIID_IBindCtx:PIID_IEnumMonikerJ PIID_IRunnableObject PIID_IRunningObjectTable!PIID_IPersisti"PIID_IPersistStream"PIID_IMonikerj#PIID_IROTDataX%PIID_IEnumSTATSTG%PIID_IStorageX&PIID_IPersistFileA(PIID_IPersistStorage(PIID_ILockBytes)PIID_IEnumFORMATETC*PIID_IEnumSTATDATAl+PIID_IRootStorage,PIID_IAdviseSink,PIID_AsyncIAdviseSinks-PIID_IAdviseSink2.PIID_AsyncIAdviseSink2./PIID_IDataObject/PIID_IDataAdviseHolder1PIID_IMessageFilter1PFMTID_SummaryInformation]2FMTID_DocSummaryInformation_2FMTID_UserDefinedPropertiesa2FMTID_DiscardableInformationc2FMTID_ImageSummaryInformatione2FMTID_AudioSummaryInformationg2FMTID_VideoSummaryInformationi2FMTID_MediaFileSummaryInformationk2IID_IClassActivators2PIID_IFillLockBytes2PIID_IProgressNotify3PIID_ILayoutStorage3PIID_IBlockingLock4PIID_ITimeAndNoticeControl4PIID_IOplockStorageN5PIID_IDirectWriterLock5PIID_IUrlMonM6PIID_IForegroundTransfer6PIID_IThumbnailExtractor7PIID_IDummyHICONIncluder7PIID_IProcessLock7PIID_ISurrogateServiceH8PIID_IInitializeSpy8PIID_IApartmentShutdown9PIID_IOleAdviseHolderPIID_IOleCachePIID_IOleCache2PIID_IOleCacheControlPIID_IParseDisplayNamePIID_IOleContainerpPIID_IOleClientSitePIID_IOleObjectPIOLETypes_v0_0_c_ifspec!IOLETypes_v0_0_s_ifspec!IID_IOleWindowPIID_IOleLinkkPIID_IOleItemContainer9PIID_IOleInPlaceUIWindowPIID_IOleInPlaceActiveObjectXPIID_IOleInPlaceFrame PIID_IOleInPlaceObject PIID_IOleInPlaceSitef PIID_IContinue, PIID_IViewObject{ PIID_IViewObject2 PIID_IDropSource9 PIID_IDropTarget PIID_IDropSourceNotify0PIID_IEnumOLEVERBPIID_IServiceProviderTPIOleAutomationTypes_v1_0_c_ifspecd!IOleAutomationTypes_v1_0_s_ifspece!IID_ICreateTypeInfoPIID_ICreateTypeInfo2 PIID_ICreateTypeLibPIID_ICreateTypeLib2PIID_IDispatchlPIID_IEnumVARIANT PIID_ITypeComp PIID_ITypeInfo] PIID_ITypeInfo2 PIID_ITypeLibPIID_ITypeLib2PIID_ITypeChangeEventsPIID_IErrorInfolPIID_ICreateErrorInfoPIID_ISupportErrorInfodPIID_ITypeFactoryPIID_ITypeMarshalPIID_IRecordInfoPIID_IErrorLogPIID_IPropertyBagP__MIDL_itf_msxml_0000_v0_0_c_ifspec!__MIDL_itf_msxml_0000_v0_0_s_ifspec!LIBID_MSXMLaIID_IXMLDOMImplementationaIID_IXMLDOMNode(aIID_IXMLDOMDocumentFragmentaIID_IXMLDOMDocumentgaIID_IXMLDOMNodeListvaIID_IXMLDOMNamedNodeMapaIID_IXMLDOMCharacterDataaIID_IXMLDOMAttributeaIID_IXMLDOMElementaIID_IXMLDOMTextaIID_IXMLDOMComment&aIID_IXMLDOMProcessingInstructionaIID_IXMLDOMCDATASectionaIID_IXMLDOMDocumentTypeaIID_IXMLDOMNotation aIID_IXMLDOMEntityaIID_IXMLDOMEntityReferenceaIID_IXMLDOMParseErrorb aIID_IXTLRuntime aDIID_XMLDOMDocumentEvents> aCLSID_DOMDocument] tCLSID_DOMFreeThreadedDocumenta tIID_IXMLHttpRequesth aCLSID_XMLHTTPRequest tIID_IXMLDSOControl aCLSID_XMLDSOControl tIID_IXMLElementCollection aIID_IXMLDocumentK aIID_IXMLDocument2 aIID_IXMLElement% aIID_IXMLElement2 aIID_IXMLAttribute aIID_IXMLError aCLSID_XMLDocument/ tCLSID_SBS_StdURLMonikerKaCLSID_SBS_HttpProtocolLaCLSID_SBS_FtpProtocolMaCLSID_SBS_GopherProtocolNaCLSID_SBS_HttpSProtocolOaCLSID_SBS_FileProtocolPaCLSID_SBS_MkProtocolQaCLSID_SBS_UrlMkBindCtxRaCLSID_SBS_SoftDistExtSaCLSID_SBS_CdlProtocolTaCLSID_SBS_ClassInstallFilterUaCLSID_SBS_InternetSecurityManagerVaCLSID_SBS_InternetZoneManagerWaIID_IAsyncMoniker`aCLSID_StdURLMonikeraaCLSID_HttpProtocolbaCLSID_FtpProtocolcaCLSID_GopherProtocoldaCLSID_HttpSProtocoleaCLSID_FileProtocolfaCLSID_MkProtocolgaCLSID_StdURLProtocolhaCLSID_UrlMkBindCtxiaCLSID_CdlProtocoljaCLSID_ClassInstallFilterkaIID_IAsyncBindCtxlaIID_IPersistMonikerPIID_IMonikerPropPIID_IBindProtocolPIID_IBindinghPIID_IBindStatusCallbackPIID_IBindStatusCallbackExPIID_IAuthenticatePIID_IAuthenticateExPIID_IHttpNegotiate^PIID_IHttpNegotiate2PIID_IHttpNegotiate3: PIID_IWinInetFileStream PIID_IWindowForBindingUI PIID_ICodeInstallz PIID_IUri PIID_IUriContainer PIID_IUriBuilder PIID_IUriBuilderFactory^PIID_IWinInetInfoPIID_IHttpSecurity6PIID_IWinInetHttpInfoPIID_IWinInetHttpTimeoutsPIID_IWinInetCacheHintsoPIID_IWinInetCacheHints2PSID_BindHost4PIID_IBindHost>PIID_IInternet`PIID_IInternetBindInfoPIID_IInternetBindInfoEx'PIID_IInternetProtocolRootPIID_IInternetProtocolIPIID_IInternetProtocolExPIID_IInternetProtocolSinkPIID_IInternetProtocolSinkStackable1PIID_IInternetSessionPIID_IInternetThreadSwitch\PIID_IInternetPriorityPIID_IInternetProtocolInfoFPCLSID_InternetSecurityManagerwaCLSID_InternetZoneManagerxaCLSID_PersistentZoneIdentifier{aIID_IInternetSecurityMgrSitePIID_IInternetSecurityManagerPIID_IInternetSecurityManagerExPIID_IInternetSecurityManagerEx2PIID_IZoneIdentifierPIID_IInternetHostSecurityManagerPGUID_CUSTOM_LOCALMACHINEZONEUNLOCKEDXPIID_IInternetZoneManagerPIID_IInternetZoneManagerExPIID_IInternetZoneManagerEx2 PCLSID_SoftDistExt!aIID_ISoftDistExt!PIID_ICatalogFileInfox"PIID_IDataFilter"PIID_IEncodingFilterFactoryp#PGUID_CUSTOM_CONFIRMOBJECTSAFETY#PIID_IWrappedProtocol#PIID_IGetBindHandleR$PIID_IBindCallbackRedirect$PIID_IPropertyStoragePIID_IPropertySetStoragePIID_IEnumSTATPROPSTG*PIID_IEnumSTATPROPSETSTGPIID_StdOleaGUID_DEVINTERFACE_DISK PGUID_DEVINTERFACE_CDROM PGUID_DEVINTERFACE_PARTITIONPGUID_DEVINTERFACE_TAPEPGUID_DEVINTERFACE_WRITEONCEDISKPGUID_DEVINTERFACE_VOLUMEPGUID_DEVINTERFACE_MEDIUMCHANGERPGUID_DEVINTERFACE_FLOPPYPGUID_DEVINTERFACE_CDCHANGERPGUID_DEVINTERFACE_STORAGEPORTPGUID_DEVINTERFACE_COMPORTPGUID_DEVINTERFACE_SERENUM_BUS_ENUMERATORP_SCARD_IO_REQUESTMdwProtocol cbPciLength SCARD_IO_REQUESTPMMg_rgSCardT0Pci%.Mg_rgSCardT1Pci%=Mg_rgSCardRawPci%LMIID_IPrintDialogCallbackPIID_IPrintDialogServicesP_commode$8@% Nosfhnd&osfile' pipech( lockinitflag) 8 lock* SegGs @ SegSs B EFlags D Dr0 H Dr1 P Dr2 X Dr3 ` Dr6 h Dr7 p Rax x Rcx Rdx Rbx Rsp Rbp Rsi Rdi R8 R9 R10 R11 R12 R13 R14 R15 Rip VectorRegister  VectorControl  DebugControl  LastBranchToRip  LastBranchFromRip  LastExceptionToRip  LastExceptionFromRip BYTEWORDDWORDr__imp__pctype+ __imp__wctype; __imp__pwctypeG   __newclmapP __newcumapQ __ptlocinfoR=__ptmbcinfoS__globallocalestatusT*__locale_changedU*__initiallocinfoV([__initiallocalestructinfoWysigned charshort intUINT_PTR /. ULONG_PTR 1.ULONG64 .DWORD64 .PVOIDPLONG1LONGLONG%ULONGLONG.  LowPart  )   LowPart  ) _LARGE_INTEGER \ u QuadPart7 LARGE_INTEGER _GUID QData1 rData2 Data3 Data4 QaGUID a_M128Aj( LowkI Highl7  M128Ams!!v __XMM_SAVE_AREA32X ControlWord StatusWord  TagWord v  Reserved1 v  ErrorOpcode  ErrorOffset  ErrorSelector Reserved2  DataOffset  DataSelector  Reserved3  MxCsr  MxCsr_Mask "FloatRegisters  "XmmRegisters  Reserved4  XMM_SAVE_AREA32#"Header"Legacy "Xmm0"Xmm1"Xmm2"Xmm3"Xmm4"Xmm5Xmm6Xmm7Xmm8 Xmm90Xmm10@Xmm11PXmm12`Xmm13pXmm14Xmm15!$%FltSaveX%FloatSaveX&r! CONTEXTXPCONTEXTR _RUNTIME_FUNCTION  BeginAddress EndAddress  UnwindData PRUNTIME_FUNCTION2 EXCEPTION_RECORD PEXCEPTION_RECORD  _EXCEPTION_POINTERS A  ContextRecord  EXCEPTION_POINTERS AGUID_MAX_POWER_SAVINGSnGUID_MIN_POWER_SAVINGSnGUID_TYPICAL_POWER_SAVINGSnNO_SUBGROUP_GUIDnALL_POWERSCHEMES_GUID nGUID_POWERSCHEME_PERSONALITY!nGUID_ACTIVE_POWERSCHEME"nGUID_IDLE_RESILIENCY_SUBGROUP#nGUID_IDLE_RESILIENCY_PERIOD$nGUID_DISK_COALESCING_POWERDOWN_TIMEOUT%nGUID_EXECUTION_REQUIRED_REQUEST_TIMEOUT&nGUID_VIDEO_SUBGROUP'nGUID_VIDEO_POWERDOWN_TIMEOUT(nGUID_VIDEO_ANNOYANCE_TIMEOUT)nGUID_VIDEO_ADAPTIVE_PERCENT_INCREASE*nGUID_VIDEO_DIM_TIMEOUT+nGUID_VIDEO_ADAPTIVE_POWERDOWN,nGUID_MONITOR_POWER_ON-nGUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS.nGUID_DEVICE_POWER_POLICY_VIDEO_DIM_BRIGHTNESS/nGUID_VIDEO_CURRENT_MONITOR_BRIGHTNESS0nGUID_VIDEO_ADAPTIVE_DISPLAY_BRIGHTNESS1nGUID_CONSOLE_DISPLAY_STATE2nGUID_ALLOW_DISPLAY_REQUIRED3nGUID_VIDEO_CONSOLE_LOCK_TIMEOUT4nGUID_ADAPTIVE_POWER_BEHAVIOR_SUBGROUP5nGUID_NON_ADAPTIVE_INPUT_TIMEOUT6nGUID_DISK_SUBGROUP7nGUID_DISK_POWERDOWN_TIMEOUT8nGUID_DISK_IDLE_TIMEOUT9nGUID_DISK_BURST_IGNORE_THRESHOLD:nGUID_DISK_ADAPTIVE_POWERDOWN;nGUID_SLEEP_SUBGROUP<nGUID_SLEEP_IDLE_THRESHOLD=nGUID_STANDBY_TIMEOUT>nGUID_UNATTEND_SLEEP_TIMEOUT?nGUID_HIBERNATE_TIMEOUT@nGUID_HIBERNATE_FASTS4_POLICYAnGUID_CRITICAL_POWER_TRANSITIONBnGUID_SYSTEM_AWAYMODECnGUID_ALLOW_AWAYMODEDnGUID_ALLOW_STANDBY_STATESEnGUID_ALLOW_RTC_WAKEFnGUID_ALLOW_SYSTEM_REQUIREDGnGUID_SYSTEM_BUTTON_SUBGROUPHnGUID_POWERBUTTON_ACTIONInGUID_SLEEPBUTTON_ACTIONJnGUID_USERINTERFACEBUTTON_ACTIONKnGUID_LIDCLOSE_ACTIONLnGUID_LIDOPEN_POWERSTATEMnGUID_BATTERY_SUBGROUPNnGUID_BATTERY_DISCHARGE_ACTION_0OnGUID_BATTERY_DISCHARGE_LEVEL_0PnGUID_BATTERY_DISCHARGE_FLAGS_0QnGUID_BATTERY_DISCHARGE_ACTION_1RnGUID_BATTERY_DISCHARGE_LEVEL_1SnGUID_BATTERY_DISCHARGE_FLAGS_1TnGUID_BATTERY_DISCHARGE_ACTION_2UnGUID_BATTERY_DISCHARGE_LEVEL_2VnGUID_BATTERY_DISCHARGE_FLAGS_2WnGUID_BATTERY_DISCHARGE_ACTION_3XnGUID_BATTERY_DISCHARGE_LEVEL_3YnGUID_BATTERY_DISCHARGE_FLAGS_3ZnGUID_PROCESSOR_SETTINGS_SUBGROUP[nGUID_PROCESSOR_THROTTLE_POLICY\nGUID_PROCESSOR_THROTTLE_MAXIMUM]nGUID_PROCESSOR_THROTTLE_MINIMUM^nGUID_PROCESSOR_ALLOW_THROTTLING_nGUID_PROCESSOR_IDLESTATE_POLICY`nGUID_PROCESSOR_PERFSTATE_POLICYanGUID_PROCESSOR_PERF_INCREASE_THRESHOLDbnGUID_PROCESSOR_PERF_DECREASE_THRESHOLDcnGUID_PROCESSOR_PERF_INCREASE_POLICYdnGUID_PROCESSOR_PERF_DECREASE_POLICYenGUID_PROCESSOR_PERF_INCREASE_TIMEfnGUID_PROCESSOR_PERF_DECREASE_TIMEgnGUID_PROCESSOR_PERF_TIME_CHECKhnGUID_PROCESSOR_PERF_BOOST_POLICYinGUID_PROCESSOR_PERF_BOOST_MODEjnGUID_PROCESSOR_IDLE_ALLOW_SCALINGknGUID_PROCESSOR_IDLE_DISABLElnGUID_PROCESSOR_IDLE_STATE_MAXIMUMmnGUID_PROCESSOR_IDLE_TIME_CHECKnnGUID_PROCESSOR_IDLE_DEMOTE_THRESHOLDonGUID_PROCESSOR_IDLE_PROMOTE_THRESHOLDpnGUID_PROCESSOR_CORE_PARKING_INCREASE_THRESHOLDqnGUID_PROCESSOR_CORE_PARKING_DECREASE_THRESHOLDrnGUID_PROCESSOR_CORE_PARKING_INCREASE_POLICYsnGUID_PROCESSOR_CORE_PARKING_DECREASE_POLICYtnGUID_PROCESSOR_CORE_PARKING_MAX_CORESunGUID_PROCESSOR_CORE_PARKING_MIN_CORESvnGUID_PROCESSOR_CORE_PARKING_INCREASE_TIMEwnGUID_PROCESSOR_CORE_PARKING_DECREASE_TIMExnGUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_DECREASE_FACTORynGUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_THRESHOLDznGUID_PROCESSOR_CORE_PARKING_AFFINITY_WEIGHTING{nGUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_DECREASE_FACTOR|nGUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_THRESHOLD}nGUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_WEIGHTING~nGUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_THRESHOLDnGUID_PROCESSOR_PARKING_CORE_OVERRIDEnGUID_PROCESSOR_PARKING_PERF_STATEnGUID_PROCESSOR_PARKING_CONCURRENCY_THRESHOLDnGUID_PROCESSOR_PARKING_HEADROOM_THRESHOLDnGUID_PROCESSOR_PERF_HISTORYnGUID_PROCESSOR_PERF_LATENCY_HINTnGUID_PROCESSOR_DISTRIBUTE_UTILITYnGUID_SYSTEM_COOLING_POLICYnGUID_LOCK_CONSOLE_ON_WAKEnGUID_DEVICE_IDLE_POLICYnGUID_ACDC_POWER_SOURCEnGUID_LIDSWITCH_STATE_CHANGEnGUID_BATTERY_PERCENTAGE_REMAININGnGUID_GLOBAL_USER_PRESENCEnGUID_SESSION_DISPLAY_STATUSnGUID_SESSION_USER_PRESENCEnGUID_IDLE_BACKGROUND_TASKnGUID_BACKGROUND_TASK_NOTIFICATIONnGUID_APPLAUNCH_BUTTONnGUID_PCIEXPRESS_SETTINGS_SUBGROUPnGUID_PCIEXPRESS_ASPM_POLICYnGUID_ENABLE_SWITCH_FORCED_SHUTDOWNnPPM_PERFSTATE_CHANGE_GUIDnPPM_PERFSTATE_DOMAIN_CHANGE_GUIDnPPM_IDLESTATE_CHANGE_GUIDnPPM_PERFSTATES_DATA_GUIDnPPM_IDLESTATES_DATA_GUIDnPPM_IDLE_ACCOUNTING_GUIDnPPM_IDLE_ACCOUNTING_EX_GUIDnPPM_THERMALCONSTRAINT_GUIDnPPM_PERFMON_PERFSTATE_GUIDnPPM_THERMAL_POLICY_CHANGE_GUIDn_FILETIME(dwLowDateTime dwHighDateTime FILETIME(VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN nVIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT nNTSTATUS) ' t)(ft_scalar!(ft_struct" (FT#F))GS_ExceptionRecord% @u@)GS_ContextRecord& `p@)GS_ExceptionPointers(!] @@*__security_cookie, 0@*__security_cookie_complement- 0@+__report_gsfailureh`@,,StackCookieh )cookiej,P-controlPCl ?=)imgBasel )establisherFramel @-fctEntrymjb)hndDatan  H.z@,1+/R `p@.@,T+/Rt/Qvh/X0.@,+/R0/Xt/w `p@/w(vx/w0vp/w80.@,+/R0.$@ -+/R @@0*@-.8@"-+/Q|0=@.- ,,1__security_init_cookie2@,-cookie4 )systime5t)@)perfctr6 H.@?-,/R@0@K-0@W-0@c-2@o-/RH33&3'4 44[[ 4 4 5abortabort(4++&4 4 4tt>4CCGNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/_newmode.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt_newmode u@int:$GNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/tlssup.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt`@Wcharlong long unsigned intlong long intuintptr_tP,wchar_tgshort unsigned intintlong intpthreadlocinfo(cithreadlocaleinfostruct`8 lc_codepage` lc_collate_cp` lc_handlep lc_id $ lc_categoryH lc_clike8 mb_cur_max8  lconv_intl_refcountZ lconv_num_refcountZ lconv_mon_refcountZ  lconv( ctype1_refcountZ0 ctype18 pctype@ pclmapH pcumapP lc_time_currXpthreadmbcinfo%+1 threadmbcinfostruct localeinfo_struct locinfoK mbcinfo_locale_tstructF tagLC_ID wLanguage wCountry wCodePageLC_ID N locale N wlocaleT Z wrefcount Z 8unsigned intlong unsigned int lconv3unsigned char __lc_time_data_PHNDLRB!8_XCPT_ACTIOND mXcptNumESigNumF 8XcptActionG !x_XcptActTabJm_XcptActTabCountK8_XcptActTabSizeL8_First_FPE_IndxM8_Num_FPEN8ULONGBOOL8DWORDfloatLPVOID`__imp__pctype+E__imp__wctype;E__imp__pwctypeGEx__newclmapP__newcumapQ__ptlocinfoRK__ptmbcinfoS__globallocalestatusT8__locale_changedU8__initiallocinfoV(i__initiallocalestructinfoW__imp___mb_cur_maxZsigned charshort intULONG_PTR1.PVOIDHANDLEULONGLONG._GUIDData1Data2Data3Data4GUIDdoublelong doubleON`_sys_errlist &P_sys_nerr $8__imp___argc Z__imp___argv N__imp___wargv "T__imp__environ B__imp__wenviron G__imp__pgmptr N__imp__wpgmptr S__imp__osplatform X)__imp__osver ])__imp__winver b)__imp__winmajor g)__imp__winminor l)_amblksiz 5`GUID_MAX_POWER_SAVINGS+GUID_MIN_POWER_SAVINGS+GUID_TYPICAL_POWER_SAVINGS+NO_SUBGROUP_GUID+ALL_POWERSCHEMES_GUID +GUID_POWERSCHEME_PERSONALITY!+GUID_ACTIVE_POWERSCHEME"+GUID_IDLE_RESILIENCY_SUBGROUP#+GUID_IDLE_RESILIENCY_PERIOD$+GUID_DISK_COALESCING_POWERDOWN_TIMEOUT%+GUID_EXECUTION_REQUIRED_REQUEST_TIMEOUT&+GUID_VIDEO_SUBGROUP'+GUID_VIDEO_POWERDOWN_TIMEOUT(+GUID_VIDEO_ANNOYANCE_TIMEOUT)+GUID_VIDEO_ADAPTIVE_PERCENT_INCREASE*+GUID_VIDEO_DIM_TIMEOUT++GUID_VIDEO_ADAPTIVE_POWERDOWN,+GUID_MONITOR_POWER_ON-+GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS.+GUID_DEVICE_POWER_POLICY_VIDEO_DIM_BRIGHTNESS/+GUID_VIDEO_CURRENT_MONITOR_BRIGHTNESS0+GUID_VIDEO_ADAPTIVE_DISPLAY_BRIGHTNESS1+GUID_CONSOLE_DISPLAY_STATE2+GUID_ALLOW_DISPLAY_REQUIRED3+GUID_VIDEO_CONSOLE_LOCK_TIMEOUT4+GUID_ADAPTIVE_POWER_BEHAVIOR_SUBGROUP5+GUID_NON_ADAPTIVE_INPUT_TIMEOUT6+GUID_DISK_SUBGROUP7+GUID_DISK_POWERDOWN_TIMEOUT8+GUID_DISK_IDLE_TIMEOUT9+GUID_DISK_BURST_IGNORE_THRESHOLD:+GUID_DISK_ADAPTIVE_POWERDOWN;+GUID_SLEEP_SUBGROUP<+GUID_SLEEP_IDLE_THRESHOLD=+GUID_STANDBY_TIMEOUT>+GUID_UNATTEND_SLEEP_TIMEOUT?+GUID_HIBERNATE_TIMEOUT@+GUID_HIBERNATE_FASTS4_POLICYA+GUID_CRITICAL_POWER_TRANSITIONB+GUID_SYSTEM_AWAYMODEC+GUID_ALLOW_AWAYMODED+GUID_ALLOW_STANDBY_STATESE+GUID_ALLOW_RTC_WAKEF+GUID_ALLOW_SYSTEM_REQUIREDG+GUID_SYSTEM_BUTTON_SUBGROUPH+GUID_POWERBUTTON_ACTIONI+GUID_SLEEPBUTTON_ACTIONJ+GUID_USERINTERFACEBUTTON_ACTIONK+GUID_LIDCLOSE_ACTIONL+GUID_LIDOPEN_POWERSTATEM+GUID_BATTERY_SUBGROUPN+GUID_BATTERY_DISCHARGE_ACTION_0O+GUID_BATTERY_DISCHARGE_LEVEL_0P+GUID_BATTERY_DISCHARGE_FLAGS_0Q+GUID_BATTERY_DISCHARGE_ACTION_1R+GUID_BATTERY_DISCHARGE_LEVEL_1S+GUID_BATTERY_DISCHARGE_FLAGS_1T+GUID_BATTERY_DISCHARGE_ACTION_2U+GUID_BATTERY_DISCHARGE_LEVEL_2V+GUID_BATTERY_DISCHARGE_FLAGS_2W+GUID_BATTERY_DISCHARGE_ACTION_3X+GUID_BATTERY_DISCHARGE_LEVEL_3Y+GUID_BATTERY_DISCHARGE_FLAGS_3Z+GUID_PROCESSOR_SETTINGS_SUBGROUP[+GUID_PROCESSOR_THROTTLE_POLICY\+GUID_PROCESSOR_THROTTLE_MAXIMUM]+GUID_PROCESSOR_THROTTLE_MINIMUM^+GUID_PROCESSOR_ALLOW_THROTTLING_+GUID_PROCESSOR_IDLESTATE_POLICY`+GUID_PROCESSOR_PERFSTATE_POLICYa+GUID_PROCESSOR_PERF_INCREASE_THRESHOLDb+GUID_PROCESSOR_PERF_DECREASE_THRESHOLDc+GUID_PROCESSOR_PERF_INCREASE_POLICYd+GUID_PROCESSOR_PERF_DECREASE_POLICYe+GUID_PROCESSOR_PERF_INCREASE_TIMEf+GUID_PROCESSOR_PERF_DECREASE_TIMEg+GUID_PROCESSOR_PERF_TIME_CHECKh+GUID_PROCESSOR_PERF_BOOST_POLICYi+GUID_PROCESSOR_PERF_BOOST_MODEj+GUID_PROCESSOR_IDLE_ALLOW_SCALINGk+GUID_PROCESSOR_IDLE_DISABLEl+GUID_PROCESSOR_IDLE_STATE_MAXIMUMm+GUID_PROCESSOR_IDLE_TIME_CHECKn+GUID_PROCESSOR_IDLE_DEMOTE_THRESHOLDo+GUID_PROCESSOR_IDLE_PROMOTE_THRESHOLDp+GUID_PROCESSOR_CORE_PARKING_INCREASE_THRESHOLDq+GUID_PROCESSOR_CORE_PARKING_DECREASE_THRESHOLDr+GUID_PROCESSOR_CORE_PARKING_INCREASE_POLICYs+GUID_PROCESSOR_CORE_PARKING_DECREASE_POLICYt+GUID_PROCESSOR_CORE_PARKING_MAX_CORESu+GUID_PROCESSOR_CORE_PARKING_MIN_CORESv+GUID_PROCESSOR_CORE_PARKING_INCREASE_TIMEw+GUID_PROCESSOR_CORE_PARKING_DECREASE_TIMEx+GUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_DECREASE_FACTORy+GUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_THRESHOLDz+GUID_PROCESSOR_CORE_PARKING_AFFINITY_WEIGHTING{+GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_DECREASE_FACTOR|+GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_THRESHOLD}+GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_WEIGHTING~+GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_THRESHOLD+GUID_PROCESSOR_PARKING_CORE_OVERRIDE+GUID_PROCESSOR_PARKING_PERF_STATE+GUID_PROCESSOR_PARKING_CONCURRENCY_THRESHOLD+GUID_PROCESSOR_PARKING_HEADROOM_THRESHOLD+GUID_PROCESSOR_PERF_HISTORY+GUID_PROCESSOR_PERF_LATENCY_HINT+GUID_PROCESSOR_DISTRIBUTE_UTILITY+GUID_SYSTEM_COOLING_POLICY+GUID_LOCK_CONSOLE_ON_WAKE+GUID_DEVICE_IDLE_POLICY+GUID_ACDC_POWER_SOURCE+GUID_LIDSWITCH_STATE_CHANGE+GUID_BATTERY_PERCENTAGE_REMAINING+GUID_GLOBAL_USER_PRESENCE+GUID_SESSION_DISPLAY_STATUS+GUID_SESSION_USER_PRESENCE+GUID_IDLE_BACKGROUND_TASK+GUID_BACKGROUND_TASK_NOTIFICATION+GUID_APPLAUNCH_BUTTON+GUID_PCIEXPRESS_SETTINGS_SUBGROUP+GUID_PCIEXPRESS_ASPM_POLICY+GUID_ENABLE_SWITCH_FORCED_SHUTDOWN+PPM_PERFSTATE_CHANGE_GUID+PPM_PERFSTATE_DOMAIN_CHANGE_GUID+PPM_IDLESTATE_CHANGE_GUID+PPM_PERFSTATES_DATA_GUID+PPM_IDLESTATES_DATA_GUID+PPM_IDLE_ACCOUNTING_GUID+PPM_IDLE_ACCOUNTING_EX_GUID+PPM_THERMALCONSTRAINT_GUID+PPM_PERFMON_PERFSTATE_GUID+PPM_THERMAL_POLICY_CHANGE_GUID+PIMAGE_TLS_CALLBACK. _IMAGE_TLS_DIRECTORY64( StartAddressOfRawData EndAddressOfRawData AddressOfIndex AddressOfCallBacks SizeOfZeroFill  Characteristics $IMAGE_TLS_DIRECTORY64.IMAGE_TLS_DIRECTORY# VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN +VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT +_PVFV I _tls_index# u@_tls_start)N @_tls_end*N @__xl_a,+ 8@__xl_z-+ P@_tls_used/3 @@@__xd_a?$ X@__xd_z@$ `@_CRT_MTG 8__dyn_tls_init_callbackg  @@__xl_ch+ @@__xl_d+ H@mingw_initltsdrot_force8 u@mingw_initltsdyn_force8 u@mingw_initltssuo_force8 u@__dyn_tls_dtor`@/"#*`\;@1$__tlregdtorm8 @#funcm R __dyn_tls_initLp#!L!L*!L;"pfuncN "psO ##@1$$2#$>#H @ $J# %V#%d#&#@@+L#$$2#  $>#S Q $J#{ w 'V# 'd# @1$(OGNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/cinitexe.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crtcharlong long unsigned intlong long intshort unsigned intintlong intunsigned intlong unsigned intunsigned char_PVFVZ`Lq__xi_a a @__xi_z a 0@__xc_a a @__xc_z a @GNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/merr.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt0@Sdoublecharlong long unsigned intlong long intshort unsigned intintlong intunsigned intlong unsigned intunsigned charfloatlong double__imp__HUGE_exception( type namearg1 arg2 retval signgam _matherr0@ pexcept 9 3 type  @y R2@ Q xA@ Xs Yt w  w( w0Pfprintffprintf+GNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/CRT_fp10.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt0@B_fpreset 0@GNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/mingw_helpers.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crtmingw_app_type v@intP`GNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/pseudo-reloc.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt@@e__gnuc_va_list__builtin_va_listcharva_listsize_t(,)long long unsigned intlong long intintptr_tC#Cptrdiff_t]#Cwchar_tgshort unsigned intintlong intpthreadlocinfo(threadlocaleinfostruct`}  lc_codepage lc_collate_cp lc_handle lc_id $ lc_categoryH lc_clike mb_cur_max  lconv_intl_refcount lconv_num_refcount lconv_mon_refcount  lconv+( ctype1_refcount0 ctype118 pctype7@ pclmap=H pcumap=P lc_time_curriXpthreadmbcinfo% threadmbcinfostruct localeinfo_struct locinfo mbcinfo}_locale_tstruct tagLC_IDY wLanguage wCountry wCodePageLC_ID   locale  wlocale   wrefcount wunsigned int)long unsigned intY)h$) lconv$Tunsigned charC __lc_time_dataY_PHNDLRB_XCPT_ACTIOND XcptNumESigNumF XcptActionG o_XcptActTabJ_XcptActTabCountK_XcptActTabSizeL_First_FPE_IndxM_Num_FPENBYTECWORDDWORDfloatPBYTEWLPBYTELPVOIDU__imp__pctype+1__imp__wctype;__imp__pwctypeGT__newclmapP__newcumapQ__ptlocinfoR__ptmbcinfoS}__globallocalestatusT__locale_changedU__initiallocinfoV(__initiallocalestructinfoW__imp___mb_cur_maxsigned charshort intULONG_PTR1.)SIZE_T'PVOIDULONGHANDLEU _LIST_ENTRYd Flinke BlinkfdLIST_ENTRYgd_GUID  Data1 Data2 Data3 Data4  C )GUID  IID X # CLSID ` 4 FMTID g G doublelong double )_sys_errlist &s _sys_nerr $__imp___argc __imp___argv   __imp___wargv "  __imp__environ B __imp__wenviron G __imp__pgmptr N __imp__wpgmptr S __imp__osplatform X__imp__osver ]__imp__winver b__imp__winmajor g__imp__winminor l_amblksiz 5 _MEMORY_BASIC_INFORMATION0 BaseAddress 7 AllocationBase 7 AllocationProtect q RegionSize( State q Protect q$ Type q(MEMORY_BASIC_INFORMATION GUID_MAX_POWER_SAVINGS GUID_MIN_POWER_SAVINGS GUID_TYPICAL_POWER_SAVINGS NO_SUBGROUP_GUID ALL_POWERSCHEMES_GUID  GUID_POWERSCHEME_PERSONALITY! GUID_ACTIVE_POWERSCHEME" GUID_IDLE_RESILIENCY_SUBGROUP# GUID_IDLE_RESILIENCY_PERIOD$ GUID_DISK_COALESCING_POWERDOWN_TIMEOUT% GUID_EXECUTION_REQUIRED_REQUEST_TIMEOUT& GUID_VIDEO_SUBGROUP' GUID_VIDEO_POWERDOWN_TIMEOUT( GUID_VIDEO_ANNOYANCE_TIMEOUT) GUID_VIDEO_ADAPTIVE_PERCENT_INCREASE* GUID_VIDEO_DIM_TIMEOUT+ GUID_VIDEO_ADAPTIVE_POWERDOWN, GUID_MONITOR_POWER_ON- GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS. GUID_DEVICE_POWER_POLICY_VIDEO_DIM_BRIGHTNESS/ GUID_VIDEO_CURRENT_MONITOR_BRIGHTNESS0 GUID_VIDEO_ADAPTIVE_DISPLAY_BRIGHTNESS1 GUID_CONSOLE_DISPLAY_STATE2 GUID_ALLOW_DISPLAY_REQUIRED3 GUID_VIDEO_CONSOLE_LOCK_TIMEOUT4 GUID_ADAPTIVE_POWER_BEHAVIOR_SUBGROUP5 GUID_NON_ADAPTIVE_INPUT_TIMEOUT6 GUID_DISK_SUBGROUP7 GUID_DISK_POWERDOWN_TIMEOUT8 GUID_DISK_IDLE_TIMEOUT9 GUID_DISK_BURST_IGNORE_THRESHOLD: GUID_DISK_ADAPTIVE_POWERDOWN; GUID_SLEEP_SUBGROUP< GUID_SLEEP_IDLE_THRESHOLD= GUID_STANDBY_TIMEOUT> GUID_UNATTEND_SLEEP_TIMEOUT? GUID_HIBERNATE_TIMEOUT@ GUID_HIBERNATE_FASTS4_POLICYA GUID_CRITICAL_POWER_TRANSITIONB GUID_SYSTEM_AWAYMODEC GUID_ALLOW_AWAYMODED GUID_ALLOW_STANDBY_STATESE GUID_ALLOW_RTC_WAKEF GUID_ALLOW_SYSTEM_REQUIREDG GUID_SYSTEM_BUTTON_SUBGROUPH GUID_POWERBUTTON_ACTIONI GUID_SLEEPBUTTON_ACTIONJ GUID_USERINTERFACEBUTTON_ACTIONK GUID_LIDCLOSE_ACTIONL GUID_LIDOPEN_POWERSTATEM GUID_BATTERY_SUBGROUPN GUID_BATTERY_DISCHARGE_ACTION_0O GUID_BATTERY_DISCHARGE_LEVEL_0P GUID_BATTERY_DISCHARGE_FLAGS_0Q GUID_BATTERY_DISCHARGE_ACTION_1R GUID_BATTERY_DISCHARGE_LEVEL_1S GUID_BATTERY_DISCHARGE_FLAGS_1T GUID_BATTERY_DISCHARGE_ACTION_2U GUID_BATTERY_DISCHARGE_LEVEL_2V GUID_BATTERY_DISCHARGE_FLAGS_2W GUID_BATTERY_DISCHARGE_ACTION_3X GUID_BATTERY_DISCHARGE_LEVEL_3Y GUID_BATTERY_DISCHARGE_FLAGS_3Z GUID_PROCESSOR_SETTINGS_SUBGROUP[ GUID_PROCESSOR_THROTTLE_POLICY\ GUID_PROCESSOR_THROTTLE_MAXIMUM] GUID_PROCESSOR_THROTTLE_MINIMUM^ GUID_PROCESSOR_ALLOW_THROTTLING_ GUID_PROCESSOR_IDLESTATE_POLICY` GUID_PROCESSOR_PERFSTATE_POLICYa GUID_PROCESSOR_PERF_INCREASE_THRESHOLDb GUID_PROCESSOR_PERF_DECREASE_THRESHOLDc GUID_PROCESSOR_PERF_INCREASE_POLICYd GUID_PROCESSOR_PERF_DECREASE_POLICYe GUID_PROCESSOR_PERF_INCREASE_TIMEf GUID_PROCESSOR_PERF_DECREASE_TIMEg GUID_PROCESSOR_PERF_TIME_CHECKh GUID_PROCESSOR_PERF_BOOST_POLICYi GUID_PROCESSOR_PERF_BOOST_MODEj GUID_PROCESSOR_IDLE_ALLOW_SCALINGk GUID_PROCESSOR_IDLE_DISABLEl GUID_PROCESSOR_IDLE_STATE_MAXIMUMm GUID_PROCESSOR_IDLE_TIME_CHECKn GUID_PROCESSOR_IDLE_DEMOTE_THRESHOLDo GUID_PROCESSOR_IDLE_PROMOTE_THRESHOLDp GUID_PROCESSOR_CORE_PARKING_INCREASE_THRESHOLDq GUID_PROCESSOR_CORE_PARKING_DECREASE_THRESHOLDr GUID_PROCESSOR_CORE_PARKING_INCREASE_POLICYs GUID_PROCESSOR_CORE_PARKING_DECREASE_POLICYt GUID_PROCESSOR_CORE_PARKING_MAX_CORESu GUID_PROCESSOR_CORE_PARKING_MIN_CORESv GUID_PROCESSOR_CORE_PARKING_INCREASE_TIMEw GUID_PROCESSOR_CORE_PARKING_DECREASE_TIMEx GUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_DECREASE_FACTORy GUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_THRESHOLDz GUID_PROCESSOR_CORE_PARKING_AFFINITY_WEIGHTING{ GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_DECREASE_FACTOR| GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_THRESHOLD} GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_WEIGHTING~ GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_THRESHOLD GUID_PROCESSOR_PARKING_CORE_OVERRIDE GUID_PROCESSOR_PARKING_PERF_STATE GUID_PROCESSOR_PARKING_CONCURRENCY_THRESHOLD GUID_PROCESSOR_PARKING_HEADROOM_THRESHOLD GUID_PROCESSOR_PERF_HISTORY GUID_PROCESSOR_PERF_LATENCY_HINT GUID_PROCESSOR_DISTRIBUTE_UTILITY GUID_SYSTEM_COOLING_POLICY GUID_LOCK_CONSOLE_ON_WAKE GUID_DEVICE_IDLE_POLICY GUID_ACDC_POWER_SOURCE GUID_LIDSWITCH_STATE_CHANGE GUID_BATTERY_PERCENTAGE_REMAINING GUID_GLOBAL_USER_PRESENCE GUID_SESSION_DISPLAY_STATUS GUID_SESSION_USER_PRESENCE GUID_IDLE_BACKGROUND_TASK GUID_BACKGROUND_TASK_NOTIFICATION GUID_APPLAUNCH_BUTTON GUID_PCIEXPRESS_SETTINGS_SUBGROUP GUID_PCIEXPRESS_ASPM_POLICY GUID_ENABLE_SWITCH_FORCED_SHUTDOWN PPM_PERFSTATE_CHANGE_GUID PPM_PERFSTATE_DOMAIN_CHANGE_GUID PPM_IDLESTATE_CHANGE_GUID PPM_PERFSTATES_DATA_GUID PPM_IDLESTATES_DATA_GUID PPM_IDLE_ACCOUNTING_GUID PPM_IDLE_ACCOUNTING_EX_GUID PPM_THERMALCONSTRAINT_GUID PPM_PERFMON_PERFSTATE_GUID PPM_THERMAL_POLICY_CHANGE_GUID W )5!PhysicalAddressqVirtualSizeq _IMAGE_SECTION_HEADER(T" Name Misc  VirtualAddress q SizeOfRawData q PointerToRawData q PointerToRelocations q PointerToLinenumbers q NumberOfRelocations d NumberOfLinenumbers d" Characteristics  q$PIMAGE_SECTION_HEADER s"5! _RTL_CRITICAL_SECTION_DEBUG05{# Type6 d CreatorBackTraceIndex7 d CriticalSection8% $ ProcessLocksList9 EntryCount: q ContentionCount; q$ Flags< q( CreatorBackTraceIndexHigh= d, SpareWORD> d. _RTL_CRITICAL_SECTION(P $ DebugInfoQ#&$ LockCountR F RecursionCountS F OwningThreadTT LockSemaphoreUT SpinCountV {#PRTL_CRITICAL_SECTION_DEBUG?#K$y"RTL_CRITICAL_SECTIONW{#CRITICAL_SECTION Q$VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN  VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT  RPC_IF_HANDLEBUtagCOINITBASE2%COINITBASE_MULTITHREADEDIWinTypesBase_v0_1_c_ifspec*$IWinTypesBase_v0_1_s_ifspec+$IID_IUnknowna IID_AsyncIUnknown IID_IClassFactory8 IID_IMarshal IID_INoMarshal IID_IAgileObject IID_IAgileReference> IID_IMarshal2 IID_IMalloc IID_IStdMarshalInfo IID_IExternalConnection IID_IMultiQIb IID_AsyncIMultiQI IID_IInternalUnknown IID_IEnumUnknownb IID_IEnumString IID_ISequentialStreamp IID_IStream IID_IRpcChannelBuffer%  IID_IRpcChannelBuffer2  IID_IAsyncRpcChannelBuffer!  IID_IRpcChannelBuffer3  IID_IRpcSyntaxNegotiate  IID_IRpcProxyBuffer  IID_IRpcStubBufferI  IID_IPSFactoryBuffer  IID_IChannelHookH  IID_IClientSecurity( IID_IServerSecurity IID_IRpcOptions0 IID_IGlobalOptions IID_ISurrogate IID_IGlobalInterfaceTablet IID_ISynchronize IID_ISynchronizeHandleF IID_ISynchronizeEvent IID_ISynchronizeContainer IID_ISynchronizeMutexJ IID_ICancelMethodCalls IID_IAsyncManager IID_ICallFactoryw IID_IRpcHelper IID_IReleaseMarshalBuffers& IID_IWaitMultiplex IID_IAddrTrackingControl IID_IAddrExclusionControl, IID_IPipeByte IID_IPipeLong IID_IPipeDoubleE IID_IComThreadingInfo IID_IProcessInitControl1 IID_IFastRundown IID_IMarshalingStream IID_ICallbackWithNoReentrancyToApplicationSTAz GUID_NULL / CATID_MARSHALER/ IID_IRpcChannel/ IID_IRpcStub/ IID_IStubManager/ IID_IRpcProxy/ IID_IProxyManager/ IID_IPSFactory/ IID_IInternalMoniker/ IID_IDfReserved1/ IID_IDfReserved2/ IID_IDfReserved3/ CLSID_StdMarshalB CLSID_AggStdMarshalB CLSID_StdAsyncActManagerB IID_IStub/ IID_IProxy/ IID_IEnumGeneric/ IID_IEnumHolder/ IID_IEnumCallback / IID_IOleManager!/ IID_IOlePresObj"/ IID_IDebug#/ IID_IDebugStream$/ CLSID_PSGenObject%B CLSID_PSClientSite&B CLSID_PSClassObject'B CLSID_PSInPlaceActive(B CLSID_PSInPlaceFrame)B CLSID_PSDragDrop*B CLSID_PSBindCtx+B CLSID_PSEnumerators,B CLSID_StaticMetafile-B CLSID_StaticDib.B CID_CDfsVolume/B CLSID_DCOMAccessControl0B CLSID_GlobalOptions1B CLSID_StdGlobalInterfaceTable2B CLSID_ComBinding3B CLSID_StdEvent4B CLSID_ManualResetEvent5B CLSID_SynchronizeContainer6B CLSID_AddrControl7B CLSID_CCDFormKrnl8B CLSID_CCDPropertyPage9B CLSID_CCDFormDialog:B CLSID_CCDCommandButton;B CLSID_CCDComboBox<B CLSID_CCDTextBox=B CLSID_CCDCheckBox>B CLSID_CCDLabel?B CLSID_CCDOptionButton@B CLSID_CCDListBoxAB CLSID_CCDScrollBarBB CLSID_CCDGroupBoxCB CLSID_CCDGeneralPropertyPageDB CLSID_CCDGenericPropertyPageEB CLSID_CCDFontPropertyPageFB CLSID_CCDColorPropertyPageGB CLSID_CCDLabelPropertyPageHB CLSID_CCDCheckBoxPropertyPageIB CLSID_CCDTextBoxPropertyPageJB CLSID_CCDOptionButtonPropertyPageKB CLSID_CCDListBoxPropertyPageLB CLSID_CCDCommandButtonPropertyPageMB CLSID_CCDComboBoxPropertyPageNB CLSID_CCDScrollBarPropertyPageOB CLSID_CCDGroupBoxPropertyPagePB CLSID_CCDXObjectPropertyPageQB CLSID_CStdPropertyFrameRB CLSID_CFormPropertyPageSB CLSID_CGridPropertyPageTB CLSID_CWSJArticlePageUB CLSID_CSystemPageVB CLSID_IdentityUnmarshalWB CLSID_InProcFreeMarshalerXB CLSID_Picture_MetafileYB CLSID_Picture_EnhMetafileZB CLSID_Picture_Dib[B GUID_TRISTATE\ IWinTypes_v0_1_c_ifspec)$IWinTypes_v0_1_s_ifspec*$VARENUMH7VT_EMPTYVT_NULLVT_I2VT_I4VT_R4VT_R8VT_CYVT_DATEVT_BSTRVT_DISPATCH VT_ERROR VT_BOOL VT_VARIANT VT_UNKNOWN VT_DECIMALVT_I1VT_UI1VT_UI2VT_UI4VT_I8VT_UI8VT_INTVT_UINTVT_VOIDVT_HRESULTVT_PTRVT_SAFEARRAYVT_CARRAYVT_USERDEFINEDVT_LPSTRVT_LPWSTRVT_RECORD$VT_INT_PTR%VT_UINT_PTR&VT_FILETIME@VT_BLOBAVT_STREAMBVT_STORAGECVT_STREAMED_OBJECTDVT_STORED_OBJECTEVT_BLOB_OBJECTFVT_CFGVT_CLSIDHVT_VERSIONED_STREAMI VT_BSTR_BLOB VT_VECTOR VT_ARRAY VT_BYREF@ VT_RESERVED VT_ILLEGAL VT_ILLEGALMASKED VT_TYPEMASKIID_IMallocSpy IID_IBindCtx: IID_IEnumMonikerJ  IID_IRunnableObject  IID_IRunningObjectTable! IID_IPersisti" IID_IPersistStream" IID_IMonikerj# IID_IROTDataX% IID_IEnumSTATSTG% IID_IStorageX& IID_IPersistFileA( IID_IPersistStorage( IID_ILockBytes) IID_IEnumFORMATETC* IID_IEnumSTATDATAl+ IID_IRootStorage, IID_IAdviseSink, IID_AsyncIAdviseSinks- IID_IAdviseSink2. IID_AsyncIAdviseSink2./ IID_IDataObject/ IID_IDataAdviseHolder1 IID_IMessageFilter1 FMTID_SummaryInformation]2U FMTID_DocSummaryInformation_2U FMTID_UserDefinedPropertiesa2U FMTID_DiscardableInformationc2U FMTID_ImageSummaryInformatione2U FMTID_AudioSummaryInformationg2U FMTID_VideoSummaryInformationi2U FMTID_MediaFileSummaryInformationk2U IID_IClassActivators2 IID_IFillLockBytes2 IID_IProgressNotify3 IID_ILayoutStorage3 IID_IBlockingLock4 IID_ITimeAndNoticeControl4 IID_IOplockStorageN5 IID_IDirectWriterLock5 IID_IUrlMonM6 IID_IForegroundTransfer6 IID_IThumbnailExtractor7 IID_IDummyHICONIncluder7 IID_IProcessLock7 IID_ISurrogateServiceH8 IID_IInitializeSpy8 IID_IApartmentShutdown9 IID_IOleAdviseHolder IID_IOleCache IID_IOleCache2 IID_IOleCacheControl IID_IParseDisplayName IID_IOleContainerp IID_IOleClientSite IID_IOleObject IOLETypes_v0_0_c_ifspec$IOLETypes_v0_0_s_ifspec$IID_IOleWindow IID_IOleLinkk IID_IOleItemContainer9 IID_IOleInPlaceUIWindow IID_IOleInPlaceActiveObjectX IID_IOleInPlaceFrame  IID_IOleInPlaceObject  IID_IOleInPlaceSitef  IID_IContinue,  IID_IViewObject{  IID_IViewObject2  IID_IDropSource9  IID_IDropTarget  IID_IDropSourceNotify0 IID_IEnumOLEVERB IID_IServiceProviderT IOleAutomationTypes_v1_0_c_ifspecd$IOleAutomationTypes_v1_0_s_ifspece$IID_ICreateTypeInfo IID_ICreateTypeInfo2  IID_ICreateTypeLib IID_ICreateTypeLib2 IID_IDispatchl IID_IEnumVARIANT  IID_ITypeComp  IID_ITypeInfo]  IID_ITypeInfo2  IID_ITypeLib IID_ITypeLib2 IID_ITypeChangeEvents IID_IErrorInfol IID_ICreateErrorInfo IID_ISupportErrorInfod IID_ITypeFactory IID_ITypeMarshal IID_IRecordInfo IID_IErrorLog IID_IPropertyBag __MIDL_itf_msxml_0000_v0_0_c_ifspec$__MIDL_itf_msxml_0000_v0_0_s_ifspec$LIBID_MSXML/ IID_IXMLDOMImplementation/ IID_IXMLDOMNode(/ IID_IXMLDOMDocumentFragment/ IID_IXMLDOMDocumentg/ IID_IXMLDOMNodeListv/ IID_IXMLDOMNamedNodeMap/ IID_IXMLDOMCharacterData/ IID_IXMLDOMAttribute/ IID_IXMLDOMElement/ IID_IXMLDOMText/ IID_IXMLDOMComment&/ IID_IXMLDOMProcessingInstruction/ IID_IXMLDOMCDATASection/ IID_IXMLDOMDocumentType/ IID_IXMLDOMNotation / IID_IXMLDOMEntity/ IID_IXMLDOMEntityReference/ IID_IXMLDOMParseErrorb / IID_IXTLRuntime / DIID_XMLDOMDocumentEvents> / CLSID_DOMDocument] B CLSID_DOMFreeThreadedDocumenta B IID_IXMLHttpRequesth / CLSID_XMLHTTPRequest B IID_IXMLDSOControl / CLSID_XMLDSOControl B IID_IXMLElementCollection / IID_IXMLDocumentK / IID_IXMLDocument2 / IID_IXMLElement% / IID_IXMLElement2 / IID_IXMLAttribute / IID_IXMLError / CLSID_XMLDocument/ B CLSID_SBS_StdURLMonikerK/ CLSID_SBS_HttpProtocolL/ CLSID_SBS_FtpProtocolM/ CLSID_SBS_GopherProtocolN/ CLSID_SBS_HttpSProtocolO/ CLSID_SBS_FileProtocolP/ CLSID_SBS_MkProtocolQ/ CLSID_SBS_UrlMkBindCtxR/ CLSID_SBS_SoftDistExtS/ CLSID_SBS_CdlProtocolT/ CLSID_SBS_ClassInstallFilterU/ CLSID_SBS_InternetSecurityManagerV/ CLSID_SBS_InternetZoneManagerW/ IID_IAsyncMoniker`/ CLSID_StdURLMonikera/ CLSID_HttpProtocolb/ CLSID_FtpProtocolc/ CLSID_GopherProtocold/ CLSID_HttpSProtocole/ CLSID_FileProtocolf/ CLSID_MkProtocolg/ CLSID_StdURLProtocolh/ CLSID_UrlMkBindCtxi/ CLSID_CdlProtocolj/ CLSID_ClassInstallFilterk/ IID_IAsyncBindCtxl/ IID_IPersistMoniker IID_IMonikerProp IID_IBindProtocol IID_IBindingh IID_IBindStatusCallback IID_IBindStatusCallbackEx IID_IAuthenticate IID_IAuthenticateEx IID_IHttpNegotiate^ IID_IHttpNegotiate2 IID_IHttpNegotiate3:  IID_IWinInetFileStream  IID_IWindowForBindingUI  IID_ICodeInstallz  IID_IUri  IID_IUriContainer  IID_IUriBuilder  IID_IUriBuilderFactory^ IID_IWinInetInfo IID_IHttpSecurity6 IID_IWinInetHttpInfo IID_IWinInetHttpTimeouts IID_IWinInetCacheHintso IID_IWinInetCacheHints2 SID_BindHost4 IID_IBindHost> IID_IInternet` IID_IInternetBindInfo IID_IInternetBindInfoEx' IID_IInternetProtocolRoot IID_IInternetProtocolI IID_IInternetProtocolEx IID_IInternetProtocolSink IID_IInternetProtocolSinkStackable1 IID_IInternetSession IID_IInternetThreadSwitch\ IID_IInternetPriority IID_IInternetProtocolInfoF CLSID_InternetSecurityManagerw/ CLSID_InternetZoneManagerx/ CLSID_PersistentZoneIdentifier{/ IID_IInternetSecurityMgrSite IID_IInternetSecurityManager IID_IInternetSecurityManagerEx IID_IInternetSecurityManagerEx2 IID_IZoneIdentifier IID_IInternetHostSecurityManager GUID_CUSTOM_LOCALMACHINEZONEUNLOCKEDX IID_IInternetZoneManager IID_IInternetZoneManagerEx IID_IInternetZoneManagerEx2  CLSID_SoftDistExt!/ IID_ISoftDistExt! IID_ICatalogFileInfox" IID_IDataFilter" IID_IEncodingFilterFactoryp# GUID_CUSTOM_CONFIRMOBJECTSAFETY# IID_IWrappedProtocol# IID_IGetBindHandleR$ IID_IBindCallbackRedirect$ IID_IPropertyStorage IID_IPropertySetStorage IID_IEnumSTATPROPSTG* IID_IEnumSTATPROPSETSTG IID_StdOle/ GUID_DEVINTERFACE_DISK  GUID_DEVINTERFACE_CDROM  GUID_DEVINTERFACE_PARTITION GUID_DEVINTERFACE_TAPE GUID_DEVINTERFACE_WRITEONCEDISK GUID_DEVINTERFACE_VOLUME GUID_DEVINTERFACE_MEDIUMCHANGER GUID_DEVINTERFACE_FLOPPY GUID_DEVINTERFACE_CDCHANGER GUID_DEVINTERFACE_STORAGEPORT GUID_DEVINTERFACE_COMPORT GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR _SCARD_IO_REQUESTSdwProtocol qcbPciLength qSCARD_IO_REQUESTGSSg_rgSCardT0Pci%.Sg_rgSCardT1Pci%=Sg_rgSCardRawPci%LSIID_IPrintDialogCallback  IID_IPrintDialogServices  _commode!$!@!% Tosfhnd!&Tosfile!' pipech!( lockinitflag!)  lock!*o$"textmode!+ 8"unicode!, 8pipech2!- T9T)ioinfo!.CTUU UT__imp___badioinfo!DT__imp___pioinfo!IT_dowildcard!f_newmode!g__imp___winitenv!j __imp___initenv!o #^!U__uninitialized__initializing__initialized$^!UU__native_startup_state!+U__native_startup_lock!-V3V%__native_dllmain_reason! __native_vcclrit_reason! __RUNTIME_PSEUDO_RELOC_LIST__0 __RUNTIME_PSEUDO_RELOC_LIST_END__1 __image_base__2 !; Waddend< qtarget= qruntime_pseudo_reloc_item_v1>V! F `WsymG qtargetH qflagsI qruntime_pseudo_reloc_item_v2J*W! L Wmagic1M qmagic2N qversionO qruntime_pseudo_reloc_v2PW&/(OXold_protect qbase_address 7region_size (sec_start hashT" $/W'the_secsvX v@OX'maxSections  v@(_pei386_runtime_relocator@[)was_init v@*mSecsB @ +[E@0[,\,%\,2\-0.@\q e /R\.c\ .y\MG.\+\%@p Y0\0\;90\`^1*@h^2Qu2X4+\@ #Z0\0\0\1@h^2Qu2X1+\6@ ~Z0\0\0\@>1A@h^2Qu2X2+\@P Z0\ec0\0\1@h^2Qu2X83\0@Qj[.\4\/\5\r@l0\&$0\LJ0\qo1w@h^2Qu2X46@][2R B@1@]2R `B@7]V@R[.+]/5]1@_2Yu8@_9do_pseudo_reloc/\:start/U:end/'U:base/3U;addr_imp1 e;reldata1e;reloc_target2 e;v2_hdr3\;r4!\<;od&\<;newvali qW`WW9__write_memory]:addrU:src):len5=restore_modified_sectionsF]>i>oldprot q=mark_section_writable]?addr>b >hT">i@__report_errorS@@jb^AmsgSb^B'argp X6m@_]2R26@_^2R A@2Q12XK6@_6^2R26@`T^2Q|2Xs8@`C\@ _0\ 0\0\5F]@ 0e]}s-/r].|].]ke6@#` _2R|8<@/`6_@;`9_2Q2X068@_W_2X@2Yu8F@G`6T@]_2R 8B@6@]_2R A@2Q|1@]2R B@D">D D#PEfwrite__builtin_fwrite%F88#2Gabortabort (DAADD"3Dvv$.tGNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/usermatherr.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt@\doublecharlong long unsigned intlong long intshort unsigned intintlong intunsigned intlong unsigned intunsigned charfloatlong double__imp__HUGE_exception( type %namearg1 arg2 retval signgam% fUserMathErr )/ %> > stUserMathErr   v@ __mingw_setusermatherr @ f,) @kRR __mingw_raise_matherr@Aktyp !%name 2JFa1 ?a2 Jrslt  ex@@R@.GNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/xtxtmode.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt_fmode 0v@inta\GNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/crt_handler.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt @p8charsize_t(,long long unsigned intlong long intwchar_tgshort unsigned intintlong intpthreadlocinfo(ekthreadlocaleinfostruct`: lc_codepageb lc_collate_cpb lc_handler lc_id $ lc_categoryH lc_clike: mb_cur_max:  lconv_intl_refcount\ lconv_num_refcount\ lconv_mon_refcount\  lconv( ctype1_refcount\0 ctype18 pctype@ pclmapH pcumapP lc_time_currXpthreadmbcinfo%-3 threadmbcinfostruct localeinfo_struct locinfoM mbcinfo_locale_tstructH tagLC_ID wLanguage wCountry wCodePageLC_ID P locale P wlocaleV \ wrefcount \:unsigned intlong unsigned int lconv5unsigned char __lc_time_data_PHNDLRB#:_XCPT_ACTIOND oXcptNumESigNumF :XcptActionG #z_XcptActTabJo_XcptActTabCountK:_XcptActTabSizeL:_First_FPE_IndxM:_Num_FPEN: _EXCEPTION_RECORD  ExceptionCode ExceptionFlags # ! ExceptionAddress  NumberParameters  ExceptionInformation A _CONTEXT% P1Home P2Home  P3Home  P4Home  P5Home P6Home ( ContextFlags 0 MxCsr 4 SegCs 8 SegDs : SegEs < SegFs > SegGs @ SegSs B EFlags D Dr0 H Dr1 P Dr2 X Dr3 ` Dr6 h Dr7 p Rax x Rcx Rdx Rbx Rsp Rbp Rsi Rdi R8 R9 R10 R11 R12 R13 R14 R15 Rip mVectorRegister  VectorControl  DebugControl  LastBranchToRip  LastBranchFromRip  LastExceptionToRip  LastExceptionFromRip ULONGBYTEWORDDWORDfloatPBYTE  LPBYTE b__imp__pctype+C __imp__wctype;C __imp__pwctypeGC  v __newclmapP __newcumapQ __ptlocinfoRM__ptmbcinfoS__globallocalestatusT:__locale_changedU:__initiallocinfoV(k__initiallocalestructinfoW__imp___mb_cur_max\signed charshort intULONG_PTR1.DWORD64.PVOIDLONGALONGLONG%ULONGLONG._GUID, Data1Data2Data3Data4, < GUID < IIDX< N CLSID`< _ FMTIDg< r _M128Aj( Lowk Highl M128Am      _doublelong doubleP _sys_errlist & _sys_nerr $:__imp___argc \__imp___argv s y P__imp___wargv "  V__imp__environ Bs __imp__wenviron G __imp__pgmptr Ny __imp__wpgmptr S __imp__osplatform X' __imp__osver ]' __imp__winver b' __imp__winmajor g' __imp__winminor l' _amblksiz 5b_XMM_SAVE_AREA32 ControlWord StatusWord  TagWord  Reserved1  ErrorOpcode  ErrorOffset  ErrorSelector Reserved2  DataOffset  DataSelector  Reserved3  MxCsr  MxCsr_Mask FloatRegisters  XmmRegisters  Reserved4 XMM_SAVE_AREA32\Header\Legacy  Xmm0 Xmm1 Xmm2 Xmm3 Xmm4 Xmm5 Xmm6 Xmm7 Xmm8  Xmm9 0Xmm10 @Xmm11 PXmm12 `Xmm13 pXmm14 Xmm15  m !FltSave!FloatSave" PCONTEXT _RUNTIME_FUNCTION ' BeginAddress EndAddress  UnwindData RUNTIME_FUNCTION| QEXCEPTION_RECORD PEXCEPTION_RECORD Q _EXCEPTION_POINTERS # k EXCEPTION_POINTERS GUID_MAX_POWER_SAVINGSI GUID_MIN_POWER_SAVINGSI GUID_TYPICAL_POWER_SAVINGSI NO_SUBGROUP_GUIDI ALL_POWERSCHEMES_GUID I GUID_POWERSCHEME_PERSONALITY!I GUID_ACTIVE_POWERSCHEME"I GUID_IDLE_RESILIENCY_SUBGROUP#I GUID_IDLE_RESILIENCY_PERIOD$I GUID_DISK_COALESCING_POWERDOWN_TIMEOUT%I GUID_EXECUTION_REQUIRED_REQUEST_TIMEOUT&I GUID_VIDEO_SUBGROUP'I GUID_VIDEO_POWERDOWN_TIMEOUT(I GUID_VIDEO_ANNOYANCE_TIMEOUT)I GUID_VIDEO_ADAPTIVE_PERCENT_INCREASE*I GUID_VIDEO_DIM_TIMEOUT+I GUID_VIDEO_ADAPTIVE_POWERDOWN,I GUID_MONITOR_POWER_ON-I GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS.I GUID_DEVICE_POWER_POLICY_VIDEO_DIM_BRIGHTNESS/I GUID_VIDEO_CURRENT_MONITOR_BRIGHTNESS0I GUID_VIDEO_ADAPTIVE_DISPLAY_BRIGHTNESS1I GUID_CONSOLE_DISPLAY_STATE2I GUID_ALLOW_DISPLAY_REQUIRED3I GUID_VIDEO_CONSOLE_LOCK_TIMEOUT4I GUID_ADAPTIVE_POWER_BEHAVIOR_SUBGROUP5I GUID_NON_ADAPTIVE_INPUT_TIMEOUT6I GUID_DISK_SUBGROUP7I GUID_DISK_POWERDOWN_TIMEOUT8I GUID_DISK_IDLE_TIMEOUT9I GUID_DISK_BURST_IGNORE_THRESHOLD:I GUID_DISK_ADAPTIVE_POWERDOWN;I GUID_SLEEP_SUBGROUP<I GUID_SLEEP_IDLE_THRESHOLD=I GUID_STANDBY_TIMEOUT>I GUID_UNATTEND_SLEEP_TIMEOUT?I GUID_HIBERNATE_TIMEOUT@I GUID_HIBERNATE_FASTS4_POLICYAI GUID_CRITICAL_POWER_TRANSITIONBI GUID_SYSTEM_AWAYMODECI GUID_ALLOW_AWAYMODEDI GUID_ALLOW_STANDBY_STATESEI GUID_ALLOW_RTC_WAKEFI GUID_ALLOW_SYSTEM_REQUIREDGI GUID_SYSTEM_BUTTON_SUBGROUPHI GUID_POWERBUTTON_ACTIONII GUID_SLEEPBUTTON_ACTIONJI GUID_USERINTERFACEBUTTON_ACTIONKI GUID_LIDCLOSE_ACTIONLI GUID_LIDOPEN_POWERSTATEMI GUID_BATTERY_SUBGROUPNI GUID_BATTERY_DISCHARGE_ACTION_0OI GUID_BATTERY_DISCHARGE_LEVEL_0PI GUID_BATTERY_DISCHARGE_FLAGS_0QI GUID_BATTERY_DISCHARGE_ACTION_1RI GUID_BATTERY_DISCHARGE_LEVEL_1SI GUID_BATTERY_DISCHARGE_FLAGS_1TI GUID_BATTERY_DISCHARGE_ACTION_2UI GUID_BATTERY_DISCHARGE_LEVEL_2VI GUID_BATTERY_DISCHARGE_FLAGS_2WI GUID_BATTERY_DISCHARGE_ACTION_3XI GUID_BATTERY_DISCHARGE_LEVEL_3YI GUID_BATTERY_DISCHARGE_FLAGS_3ZI GUID_PROCESSOR_SETTINGS_SUBGROUP[I GUID_PROCESSOR_THROTTLE_POLICY\I GUID_PROCESSOR_THROTTLE_MAXIMUM]I GUID_PROCESSOR_THROTTLE_MINIMUM^I GUID_PROCESSOR_ALLOW_THROTTLING_I GUID_PROCESSOR_IDLESTATE_POLICY`I GUID_PROCESSOR_PERFSTATE_POLICYaI GUID_PROCESSOR_PERF_INCREASE_THRESHOLDbI GUID_PROCESSOR_PERF_DECREASE_THRESHOLDcI GUID_PROCESSOR_PERF_INCREASE_POLICYdI GUID_PROCESSOR_PERF_DECREASE_POLICYeI GUID_PROCESSOR_PERF_INCREASE_TIMEfI GUID_PROCESSOR_PERF_DECREASE_TIMEgI GUID_PROCESSOR_PERF_TIME_CHECKhI GUID_PROCESSOR_PERF_BOOST_POLICYiI GUID_PROCESSOR_PERF_BOOST_MODEjI GUID_PROCESSOR_IDLE_ALLOW_SCALINGkI GUID_PROCESSOR_IDLE_DISABLElI GUID_PROCESSOR_IDLE_STATE_MAXIMUMmI GUID_PROCESSOR_IDLE_TIME_CHECKnI GUID_PROCESSOR_IDLE_DEMOTE_THRESHOLDoI GUID_PROCESSOR_IDLE_PROMOTE_THRESHOLDpI GUID_PROCESSOR_CORE_PARKING_INCREASE_THRESHOLDqI GUID_PROCESSOR_CORE_PARKING_DECREASE_THRESHOLDrI GUID_PROCESSOR_CORE_PARKING_INCREASE_POLICYsI GUID_PROCESSOR_CORE_PARKING_DECREASE_POLICYtI GUID_PROCESSOR_CORE_PARKING_MAX_CORESuI GUID_PROCESSOR_CORE_PARKING_MIN_CORESvI GUID_PROCESSOR_CORE_PARKING_INCREASE_TIMEwI GUID_PROCESSOR_CORE_PARKING_DECREASE_TIMExI GUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_DECREASE_FACTORyI GUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_THRESHOLDzI GUID_PROCESSOR_CORE_PARKING_AFFINITY_WEIGHTING{I GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_DECREASE_FACTOR|I GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_THRESHOLD}I GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_WEIGHTING~I GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_THRESHOLDI GUID_PROCESSOR_PARKING_CORE_OVERRIDEI GUID_PROCESSOR_PARKING_PERF_STATEI GUID_PROCESSOR_PARKING_CONCURRENCY_THRESHOLDI GUID_PROCESSOR_PARKING_HEADROOM_THRESHOLDI GUID_PROCESSOR_PERF_HISTORYI GUID_PROCESSOR_PERF_LATENCY_HINTI GUID_PROCESSOR_DISTRIBUTE_UTILITYI GUID_SYSTEM_COOLING_POLICYI GUID_LOCK_CONSOLE_ON_WAKEI GUID_DEVICE_IDLE_POLICYI GUID_ACDC_POWER_SOURCEI GUID_LIDSWITCH_STATE_CHANGEI GUID_BATTERY_PERCENTAGE_REMAININGI GUID_GLOBAL_USER_PRESENCEI GUID_SESSION_DISPLAY_STATUSI GUID_SESSION_USER_PRESENCEI GUID_IDLE_BACKGROUND_TASKI GUID_BACKGROUND_TASK_NOTIFICATIONI GUID_APPLAUNCH_BUTTONI GUID_PCIEXPRESS_SETTINGS_SUBGROUPI GUID_PCIEXPRESS_ASPM_POLICYI GUID_ENABLE_SWITCH_FORCED_SHUTDOWNI PPM_PERFSTATE_CHANGE_GUIDI PPM_PERFSTATE_DOMAIN_CHANGE_GUIDI PPM_IDLESTATE_CHANGE_GUIDI PPM_PERFSTATES_DATA_GUIDI PPM_IDLESTATES_DATA_GUIDI PPM_IDLE_ACCOUNTING_GUIDI PPM_IDLE_ACCOUNTING_EX_GUIDI PPM_THERMALCONSTRAINT_GUIDI PPM_PERFMON_PERFSTATE_GUIDI PPM_THERMAL_POLICY_CHANGE_GUIDI  ( _IMAGE_DOS_HEADER@q) e_magicr e_cblps  e_cpt  e_crlcu  e_cparhdrv  e_minallocw e_maxallocx e_ssy  e_spz  e_csum{  e_ip|  e_cs}  e_lfarlc~  e_ovno  e_res ) e_oemid $ e_oeminfo & e_res2 )( e_lfanew < ) ) IMAGE_DOS_HEADER(#)$PhysicalAddress $VirtualSize _IMAGE_SECTION_HEADER(+ Name ( Misc ) VirtualAddress SizeOfRawData  PointerToRawData  PointerToRelocations  PointerToLinenumbers  NumberOfRelocations NumberOfLinenumbers " Characteristics  $PIMAGE_SECTION_HEADER 6+)B+% Q+PTOP_LEVEL_EXCEPTION_FILTER <+LPTOP_LEVEL_EXCEPTION_FILTER %Q+VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN I VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT I RPC_IF_HANDLE B&tagCOINITBASEbD,'COINITBASE_MULTITHREADEDIWinTypesBase_v0_1_c_ifspec*+IWinTypesBase_v0_1_s_ifspec++IID_IUnknownaI IID_AsyncIUnknownI IID_IClassFactory8I IID_IMarshalI IID_INoMarshalI IID_IAgileObjectI IID_IAgileReference>I IID_IMarshal2I IID_IMallocI IID_IStdMarshalInfoI IID_IExternalConnectionI IID_IMultiQIbI IID_AsyncIMultiQII IID_IInternalUnknownI IID_IEnumUnknownbI IID_IEnumStringI IID_ISequentialStreampI IID_IStreamI IID_IRpcChannelBuffer% I IID_IRpcChannelBuffer2 I IID_IAsyncRpcChannelBuffer! I IID_IRpcChannelBuffer3 I IID_IRpcSyntaxNegotiate I IID_IRpcProxyBuffer I IID_IRpcStubBufferI I IID_IPSFactoryBuffer I IID_IChannelHookH I IID_IClientSecurity(I IID_IServerSecurityI IID_IRpcOptions0I IID_IGlobalOptionsI IID_ISurrogateI IID_IGlobalInterfaceTabletI IID_ISynchronizeI IID_ISynchronizeHandleFI IID_ISynchronizeEventI IID_ISynchronizeContainerI IID_ISynchronizeMutexJI IID_ICancelMethodCallsI IID_IAsyncManagerI IID_ICallFactorywI IID_IRpcHelperI IID_IReleaseMarshalBuffers&I IID_IWaitMultiplexI IID_IAddrTrackingControlI IID_IAddrExclusionControl,I IID_IPipeByteI IID_IPipeLongI IID_IPipeDoubleEI IID_IComThreadingInfoI IID_IProcessInitControl1I IID_IFastRundownI IID_IMarshalingStreamI IID_ICallbackWithNoReentrancyToApplicationSTAzI GUID_NULL Z CATID_MARSHALERZ IID_IRpcChannelZ IID_IRpcStubZ IID_IStubManagerZ IID_IRpcProxyZ IID_IProxyManagerZ IID_IPSFactoryZ IID_IInternalMonikerZ IID_IDfReserved1Z IID_IDfReserved2Z IID_IDfReserved3Z CLSID_StdMarshalm CLSID_AggStdMarshalm CLSID_StdAsyncActManagerm IID_IStubZ IID_IProxyZ IID_IEnumGenericZ IID_IEnumHolderZ IID_IEnumCallback Z IID_IOleManager!Z IID_IOlePresObj"Z IID_IDebug#Z IID_IDebugStream$Z CLSID_PSGenObject%m CLSID_PSClientSite&m CLSID_PSClassObject'm CLSID_PSInPlaceActive(m CLSID_PSInPlaceFrame)m CLSID_PSDragDrop*m CLSID_PSBindCtx+m CLSID_PSEnumerators,m CLSID_StaticMetafile-m CLSID_StaticDib.m CID_CDfsVolume/m CLSID_DCOMAccessControl0m CLSID_GlobalOptions1m CLSID_StdGlobalInterfaceTable2m CLSID_ComBinding3m CLSID_StdEvent4m CLSID_ManualResetEvent5m CLSID_SynchronizeContainer6m CLSID_AddrControl7m CLSID_CCDFormKrnl8m CLSID_CCDPropertyPage9m CLSID_CCDFormDialog:m CLSID_CCDCommandButton;m CLSID_CCDComboBox<m CLSID_CCDTextBox=m CLSID_CCDCheckBox>m CLSID_CCDLabel?m CLSID_CCDOptionButton@m CLSID_CCDListBoxAm CLSID_CCDScrollBarBm CLSID_CCDGroupBoxCm CLSID_CCDGeneralPropertyPageDm CLSID_CCDGenericPropertyPageEm CLSID_CCDFontPropertyPageFm CLSID_CCDColorPropertyPageGm CLSID_CCDLabelPropertyPageHm CLSID_CCDCheckBoxPropertyPageIm CLSID_CCDTextBoxPropertyPageJm CLSID_CCDOptionButtonPropertyPageKm CLSID_CCDListBoxPropertyPageLm CLSID_CCDCommandButtonPropertyPageMm CLSID_CCDComboBoxPropertyPageNm CLSID_CCDScrollBarPropertyPageOm CLSID_CCDGroupBoxPropertyPagePm CLSID_CCDXObjectPropertyPageQm CLSID_CStdPropertyFrameRm CLSID_CFormPropertyPageSm CLSID_CGridPropertyPageTm CLSID_CWSJArticlePageUm CLSID_CSystemPageVm CLSID_IdentityUnmarshalWm CLSID_InProcFreeMarshalerXm CLSID_Picture_MetafileYm CLSID_Picture_EnhMetafileZm CLSID_Picture_Dib[m GUID_TRISTATE\I IWinTypes_v0_1_c_ifspec)+IWinTypes_v0_1_s_ifspec*+(VARENUMbZ>'VT_EMPTY'VT_NULL'VT_I2'VT_I4'VT_R4'VT_R8'VT_CY'VT_DATE'VT_BSTR'VT_DISPATCH 'VT_ERROR 'VT_BOOL 'VT_VARIANT 'VT_UNKNOWN 'VT_DECIMAL'VT_I1'VT_UI1'VT_UI2'VT_UI4'VT_I8'VT_UI8'VT_INT'VT_UINT'VT_VOID'VT_HRESULT'VT_PTR'VT_SAFEARRAY'VT_CARRAY'VT_USERDEFINED'VT_LPSTR'VT_LPWSTR'VT_RECORD$'VT_INT_PTR%'VT_UINT_PTR&'VT_FILETIME@'VT_BLOBA'VT_STREAMB'VT_STORAGEC'VT_STREAMED_OBJECTD'VT_STORED_OBJECTE'VT_BLOB_OBJECTF'VT_CFG'VT_CLSIDH'VT_VERSIONED_STREAMI)VT_BSTR_BLOB)VT_VECTOR)VT_ARRAY )VT_BYREF@)VT_RESERVED)VT_ILLEGAL)VT_ILLEGALMASKED)VT_TYPEMASKIID_IMallocSpyI IID_IBindCtx:I IID_IEnumMonikerJ I IID_IRunnableObject I IID_IRunningObjectTable!I IID_IPersisti"I IID_IPersistStream"I IID_IMonikerj#I IID_IROTDataX%I IID_IEnumSTATSTG%I IID_IStorageX&I IID_IPersistFileA(I IID_IPersistStorage(I IID_ILockBytes)I IID_IEnumFORMATETC*I IID_IEnumSTATDATAl+I IID_IRootStorage,I IID_IAdviseSink,I IID_AsyncIAdviseSinks-I IID_IAdviseSink2.I IID_AsyncIAdviseSink2./I IID_IDataObject/I IID_IDataAdviseHolder1I IID_IMessageFilter1I FMTID_SummaryInformation]2 FMTID_DocSummaryInformation_2 FMTID_UserDefinedPropertiesa2 FMTID_DiscardableInformationc2 FMTID_ImageSummaryInformatione2 FMTID_AudioSummaryInformationg2 FMTID_VideoSummaryInformationi2 FMTID_MediaFileSummaryInformationk2 IID_IClassActivators2I IID_IFillLockBytes2I IID_IProgressNotify3I IID_ILayoutStorage3I IID_IBlockingLock4I IID_ITimeAndNoticeControl4I IID_IOplockStorageN5I IID_IDirectWriterLock5I IID_IUrlMonM6I IID_IForegroundTransfer6I IID_IThumbnailExtractor7I IID_IDummyHICONIncluder7I IID_IProcessLock7I IID_ISurrogateServiceH8I IID_IInitializeSpy8I IID_IApartmentShutdown9I IID_IOleAdviseHolderI IID_IOleCacheI IID_IOleCache2I IID_IOleCacheControlI IID_IParseDisplayNameI IID_IOleContainerpI IID_IOleClientSiteI IID_IOleObjectI IOLETypes_v0_0_c_ifspec+IOLETypes_v0_0_s_ifspec+IID_IOleWindowI IID_IOleLinkkI IID_IOleItemContainer9I IID_IOleInPlaceUIWindowI IID_IOleInPlaceActiveObjectXI IID_IOleInPlaceFrame I IID_IOleInPlaceObject I IID_IOleInPlaceSitef I IID_IContinue, I IID_IViewObject{ I IID_IViewObject2 I IID_IDropSource9 I IID_IDropTarget I IID_IDropSourceNotify0I IID_IEnumOLEVERBI IID_IServiceProviderTI IOleAutomationTypes_v1_0_c_ifspecd+IOleAutomationTypes_v1_0_s_ifspece+IID_ICreateTypeInfoI IID_ICreateTypeInfo2 I IID_ICreateTypeLibI IID_ICreateTypeLib2I IID_IDispatchlI IID_IEnumVARIANT I IID_ITypeComp I IID_ITypeInfo] I IID_ITypeInfo2 I IID_ITypeLibI IID_ITypeLib2I IID_ITypeChangeEventsI IID_IErrorInfolI IID_ICreateErrorInfoI IID_ISupportErrorInfodI IID_ITypeFactoryI IID_ITypeMarshalI IID_IRecordInfoI IID_IErrorLogI IID_IPropertyBagI __MIDL_itf_msxml_0000_v0_0_c_ifspec+__MIDL_itf_msxml_0000_v0_0_s_ifspec+LIBID_MSXMLZ IID_IXMLDOMImplementationZ IID_IXMLDOMNode(Z IID_IXMLDOMDocumentFragmentZ IID_IXMLDOMDocumentgZ IID_IXMLDOMNodeListvZ IID_IXMLDOMNamedNodeMapZ IID_IXMLDOMCharacterDataZ IID_IXMLDOMAttributeZ IID_IXMLDOMElementZ IID_IXMLDOMTextZ IID_IXMLDOMComment&Z IID_IXMLDOMProcessingInstructionZ IID_IXMLDOMCDATASectionZ IID_IXMLDOMDocumentTypeZ IID_IXMLDOMNotation Z IID_IXMLDOMEntityZ IID_IXMLDOMEntityReferenceZ IID_IXMLDOMParseErrorb Z IID_IXTLRuntime Z DIID_XMLDOMDocumentEvents> Z CLSID_DOMDocument] m CLSID_DOMFreeThreadedDocumenta m IID_IXMLHttpRequesth Z CLSID_XMLHTTPRequest m IID_IXMLDSOControl Z CLSID_XMLDSOControl m IID_IXMLElementCollection Z IID_IXMLDocumentK Z IID_IXMLDocument2 Z IID_IXMLElement% Z IID_IXMLElement2 Z IID_IXMLAttribute Z IID_IXMLError Z CLSID_XMLDocument/ m CLSID_SBS_StdURLMonikerKZ CLSID_SBS_HttpProtocolLZ CLSID_SBS_FtpProtocolMZ CLSID_SBS_GopherProtocolNZ CLSID_SBS_HttpSProtocolOZ CLSID_SBS_FileProtocolPZ CLSID_SBS_MkProtocolQZ CLSID_SBS_UrlMkBindCtxRZ CLSID_SBS_SoftDistExtSZ CLSID_SBS_CdlProtocolTZ CLSID_SBS_ClassInstallFilterUZ CLSID_SBS_InternetSecurityManagerVZ CLSID_SBS_InternetZoneManagerWZ IID_IAsyncMoniker`Z CLSID_StdURLMonikeraZ CLSID_HttpProtocolbZ CLSID_FtpProtocolcZ CLSID_GopherProtocoldZ CLSID_HttpSProtocoleZ CLSID_FileProtocolfZ CLSID_MkProtocolgZ CLSID_StdURLProtocolhZ CLSID_UrlMkBindCtxiZ CLSID_CdlProtocoljZ CLSID_ClassInstallFilterkZ IID_IAsyncBindCtxlZ IID_IPersistMonikerI IID_IMonikerPropI IID_IBindProtocolI IID_IBindinghI IID_IBindStatusCallbackI IID_IBindStatusCallbackExI IID_IAuthenticateI IID_IAuthenticateExI IID_IHttpNegotiate^I IID_IHttpNegotiate2I IID_IHttpNegotiate3: I IID_IWinInetFileStream I IID_IWindowForBindingUI I IID_ICodeInstallz I IID_IUri I IID_IUriContainer I IID_IUriBuilder I IID_IUriBuilderFactory^I IID_IWinInetInfoI IID_IHttpSecurity6I IID_IWinInetHttpInfoI IID_IWinInetHttpTimeoutsI IID_IWinInetCacheHintsoI IID_IWinInetCacheHints2I SID_BindHost4I IID_IBindHost>I IID_IInternet`I IID_IInternetBindInfoI IID_IInternetBindInfoEx'I IID_IInternetProtocolRootI IID_IInternetProtocolII IID_IInternetProtocolExI IID_IInternetProtocolSinkI IID_IInternetProtocolSinkStackable1I IID_IInternetSessionI IID_IInternetThreadSwitch\I IID_IInternetPriorityI IID_IInternetProtocolInfoFI CLSID_InternetSecurityManagerwZ CLSID_InternetZoneManagerxZ CLSID_PersistentZoneIdentifier{Z IID_IInternetSecurityMgrSiteI IID_IInternetSecurityManagerI IID_IInternetSecurityManagerExI IID_IInternetSecurityManagerEx2I IID_IZoneIdentifierI IID_IInternetHostSecurityManagerI GUID_CUSTOM_LOCALMACHINEZONEUNLOCKEDXI IID_IInternetZoneManagerI IID_IInternetZoneManagerExI IID_IInternetZoneManagerEx2 I CLSID_SoftDistExt!Z IID_ISoftDistExt!I IID_ICatalogFileInfox"I IID_IDataFilter"I IID_IEncodingFilterFactoryp#I GUID_CUSTOM_CONFIRMOBJECTSAFETY#I IID_IWrappedProtocol#I IID_IGetBindHandleR$I IID_IBindCallbackRedirect$I IID_IPropertyStorageI IID_IPropertySetStorageI IID_IEnumSTATPROPSTG*I IID_IEnumSTATPROPSETSTGI IID_StdOleZ GUID_DEVINTERFACE_DISK I GUID_DEVINTERFACE_CDROM I GUID_DEVINTERFACE_PARTITIONI GUID_DEVINTERFACE_TAPEI GUID_DEVINTERFACE_WRITEONCEDISKI GUID_DEVINTERFACE_VOLUMEI GUID_DEVINTERFACE_MEDIUMCHANGERI GUID_DEVINTERFACE_FLOPPYI GUID_DEVINTERFACE_CDCHANGERI GUID_DEVINTERFACE_STORAGEPORTI GUID_DEVINTERFACE_COMPORTI GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATORI _SCARD_IO_REQUESTZdwProtocol cbPciLength SCARD_IO_REQUESTYZZg_rgSCardT0Pci%.Zg_rgSCardT1Pci%=Zg_rgSCardRawPci%LZIID_IPrintDialogCallbackI IID_IPrintDialogServicesI __p_sig_fn_t 0__image_base__)_UNWIND_INFO\VersionAndFlags PrologSize CountOfUnwindCodes FrameRegisterAndOffset AddressOfExceptionHandler UNWIND_INFO!p['7\*emu_pdata/'\ `w@\c\*emu_xdata0S\ `v@+__mingw_oldexcpt_handleru+ @v@,_gnu_exception_handlerA"@u^-exception_data-u^. /actionA|.:0*#@waY]1R81Q00C#@wau]1R81Q12H#@a0#@wa]1R41Q03#@]1R44#@]1RR0#@wa]1R81Q03#@]1R80$@wa^1R;1Q03&$@$^1R;0?$@wa@^1R41Q10_$@wa\^1R81Q15x$@wa1R;1Q1,__mingw_SEH_error_handler^: @`6#^6WC-EstablisherFrame_ H46`9%-DispatcherContexta */actionc:.d  .e:0N @way_1R81Q00g @wa_1R81Q12l @a0 @wa_1R41Q03 @_1R40 @wa_1R81Q03!@`1R80,!@wa`1R;1Q03>!@/`1R;0!@waK`1R41Q10!@wag`1R81Q15!@wa1R;1Q1,__mingw_init_ehandler3:!@wa*was_here5: Hv@/e6   /pSec7+ /_ImageBase8  2!@a0"@a=a1R B@0"@aUa1R|5"@a1R `w@1Xt7signalsignal <833[ 8&8$8%9&GNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/tlsthrd.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt$@`p!charlong long unsigned intlong long intwchar_tg short unsigned int int'long intpthreadlocinfo(W]threadlocaleinfostruct` o' lc_codepageT lc_collate_cpT lc_handled lc_id $ lc_categoryH lc_clike' mb_cur_max'  lconv_intl_refcountN lconv_num_refcountN lconv_mon_refcountN  lconv( ctype1_refcountN0 ctype18 pctype@ pclmapH pcumapP lc_time_currXpthreadmbcinfo%% threadmbcinfostruct localeinfo_struct{ locinfo? mbcinfo_locale_tstruct: tagLC_ID wLanguage  wCountry  wCodePage LC_ID B locale B wlocaleH o N wrefcount N'unsigned intttlong unsigned int lconv "unsigned char __lc_time_data_PHNDLRB '_XCPT_ACTIOND aXcptNumEtSigNumF 'XcptActionG l_XcptActTabJa_XcptActTabCountK'_XcptActTabSizeL'_First_FPE_IndxM'_Num_FPEN'WINBOOL 'WORD DWORDtfloatLPVOIDT__imp__pctype+;__imp__wctype;;__imp__pwctypeG;yn__newclmapPy__newcumapQy__ptlocinfoR?__ptmbcinfoS__globallocalestatusT'__locale_changedU'__initiallocinfoV(]__initiallocalestructinfoW{__imp___mb_cur_maxNsigned charshort intULONG_PTR1.LONG3HANDLE _LIST_ENTRYd Flinke BlinkfLIST_ENTRYg_GUIDAData1tData2 Data3 Data4AQGUIDQdoublelong doubleB_sys_errlist &|_sys_nerr $'__imp___argc N__imp___argv B__imp___wargv "  H__imp__environ B__imp__wenviron G __imp__pgmptr N__imp__wpgmptr S __imp__osplatform X__imp__osver ]__imp__winver b__imp__winmajor g__imp__winminor l_amblksiz 5TGUID_MAX_POWER_SAVINGS^GUID_MIN_POWER_SAVINGS^GUID_TYPICAL_POWER_SAVINGS^NO_SUBGROUP_GUID^ALL_POWERSCHEMES_GUID ^GUID_POWERSCHEME_PERSONALITY!^GUID_ACTIVE_POWERSCHEME"^GUID_IDLE_RESILIENCY_SUBGROUP#^GUID_IDLE_RESILIENCY_PERIOD$^GUID_DISK_COALESCING_POWERDOWN_TIMEOUT%^GUID_EXECUTION_REQUIRED_REQUEST_TIMEOUT&^GUID_VIDEO_SUBGROUP'^GUID_VIDEO_POWERDOWN_TIMEOUT(^GUID_VIDEO_ANNOYANCE_TIMEOUT)^GUID_VIDEO_ADAPTIVE_PERCENT_INCREASE*^GUID_VIDEO_DIM_TIMEOUT+^GUID_VIDEO_ADAPTIVE_POWERDOWN,^GUID_MONITOR_POWER_ON-^GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS.^GUID_DEVICE_POWER_POLICY_VIDEO_DIM_BRIGHTNESS/^GUID_VIDEO_CURRENT_MONITOR_BRIGHTNESS0^GUID_VIDEO_ADAPTIVE_DISPLAY_BRIGHTNESS1^GUID_CONSOLE_DISPLAY_STATE2^GUID_ALLOW_DISPLAY_REQUIRED3^GUID_VIDEO_CONSOLE_LOCK_TIMEOUT4^GUID_ADAPTIVE_POWER_BEHAVIOR_SUBGROUP5^GUID_NON_ADAPTIVE_INPUT_TIMEOUT6^GUID_DISK_SUBGROUP7^GUID_DISK_POWERDOWN_TIMEOUT8^GUID_DISK_IDLE_TIMEOUT9^GUID_DISK_BURST_IGNORE_THRESHOLD:^GUID_DISK_ADAPTIVE_POWERDOWN;^GUID_SLEEP_SUBGROUP<^GUID_SLEEP_IDLE_THRESHOLD=^GUID_STANDBY_TIMEOUT>^GUID_UNATTEND_SLEEP_TIMEOUT?^GUID_HIBERNATE_TIMEOUT@^GUID_HIBERNATE_FASTS4_POLICYA^GUID_CRITICAL_POWER_TRANSITIONB^GUID_SYSTEM_AWAYMODEC^GUID_ALLOW_AWAYMODED^GUID_ALLOW_STANDBY_STATESE^GUID_ALLOW_RTC_WAKEF^GUID_ALLOW_SYSTEM_REQUIREDG^GUID_SYSTEM_BUTTON_SUBGROUPH^GUID_POWERBUTTON_ACTIONI^GUID_SLEEPBUTTON_ACTIONJ^GUID_USERINTERFACEBUTTON_ACTIONK^GUID_LIDCLOSE_ACTIONL^GUID_LIDOPEN_POWERSTATEM^GUID_BATTERY_SUBGROUPN^GUID_BATTERY_DISCHARGE_ACTION_0O^GUID_BATTERY_DISCHARGE_LEVEL_0P^GUID_BATTERY_DISCHARGE_FLAGS_0Q^GUID_BATTERY_DISCHARGE_ACTION_1R^GUID_BATTERY_DISCHARGE_LEVEL_1S^GUID_BATTERY_DISCHARGE_FLAGS_1T^GUID_BATTERY_DISCHARGE_ACTION_2U^GUID_BATTERY_DISCHARGE_LEVEL_2V^GUID_BATTERY_DISCHARGE_FLAGS_2W^GUID_BATTERY_DISCHARGE_ACTION_3X^GUID_BATTERY_DISCHARGE_LEVEL_3Y^GUID_BATTERY_DISCHARGE_FLAGS_3Z^GUID_PROCESSOR_SETTINGS_SUBGROUP[^GUID_PROCESSOR_THROTTLE_POLICY\^GUID_PROCESSOR_THROTTLE_MAXIMUM]^GUID_PROCESSOR_THROTTLE_MINIMUM^^GUID_PROCESSOR_ALLOW_THROTTLING_^GUID_PROCESSOR_IDLESTATE_POLICY`^GUID_PROCESSOR_PERFSTATE_POLICYa^GUID_PROCESSOR_PERF_INCREASE_THRESHOLDb^GUID_PROCESSOR_PERF_DECREASE_THRESHOLDc^GUID_PROCESSOR_PERF_INCREASE_POLICYd^GUID_PROCESSOR_PERF_DECREASE_POLICYe^GUID_PROCESSOR_PERF_INCREASE_TIMEf^GUID_PROCESSOR_PERF_DECREASE_TIMEg^GUID_PROCESSOR_PERF_TIME_CHECKh^GUID_PROCESSOR_PERF_BOOST_POLICYi^GUID_PROCESSOR_PERF_BOOST_MODEj^GUID_PROCESSOR_IDLE_ALLOW_SCALINGk^GUID_PROCESSOR_IDLE_DISABLEl^GUID_PROCESSOR_IDLE_STATE_MAXIMUMm^GUID_PROCESSOR_IDLE_TIME_CHECKn^GUID_PROCESSOR_IDLE_DEMOTE_THRESHOLDo^GUID_PROCESSOR_IDLE_PROMOTE_THRESHOLDp^GUID_PROCESSOR_CORE_PARKING_INCREASE_THRESHOLDq^GUID_PROCESSOR_CORE_PARKING_DECREASE_THRESHOLDr^GUID_PROCESSOR_CORE_PARKING_INCREASE_POLICYs^GUID_PROCESSOR_CORE_PARKING_DECREASE_POLICYt^GUID_PROCESSOR_CORE_PARKING_MAX_CORESu^GUID_PROCESSOR_CORE_PARKING_MIN_CORESv^GUID_PROCESSOR_CORE_PARKING_INCREASE_TIMEw^GUID_PROCESSOR_CORE_PARKING_DECREASE_TIMEx^GUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_DECREASE_FACTORy^GUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_THRESHOLDz^GUID_PROCESSOR_CORE_PARKING_AFFINITY_WEIGHTING{^GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_DECREASE_FACTOR|^GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_THRESHOLD}^GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_WEIGHTING~^GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_THRESHOLD^GUID_PROCESSOR_PARKING_CORE_OVERRIDE^GUID_PROCESSOR_PARKING_PERF_STATE^GUID_PROCESSOR_PARKING_CONCURRENCY_THRESHOLD^GUID_PROCESSOR_PARKING_HEADROOM_THRESHOLD^GUID_PROCESSOR_PERF_HISTORY^GUID_PROCESSOR_PERF_LATENCY_HINT^GUID_PROCESSOR_DISTRIBUTE_UTILITY^GUID_SYSTEM_COOLING_POLICY^GUID_LOCK_CONSOLE_ON_WAKE^GUID_DEVICE_IDLE_POLICY^GUID_ACDC_POWER_SOURCE^GUID_LIDSWITCH_STATE_CHANGE^GUID_BATTERY_PERCENTAGE_REMAINING^GUID_GLOBAL_USER_PRESENCE^GUID_SESSION_DISPLAY_STATUS^GUID_SESSION_USER_PRESENCE^GUID_IDLE_BACKGROUND_TASK^GUID_BACKGROUND_TASK_NOTIFICATION^GUID_APPLAUNCH_BUTTON^GUID_PCIEXPRESS_SETTINGS_SUBGROUP^GUID_PCIEXPRESS_ASPM_POLICY^GUID_ENABLE_SWITCH_FORCED_SHUTDOWN^PPM_PERFSTATE_CHANGE_GUID^PPM_PERFSTATE_DOMAIN_CHANGE_GUID^PPM_IDLESTATE_CHANGE_GUID^PPM_PERFSTATES_DATA_GUID^PPM_IDLESTATES_DATA_GUID^PPM_IDLE_ACCOUNTING_GUID^PPM_IDLE_ACCOUNTING_EX_GUID^PPM_THERMALCONSTRAINT_GUID^PPM_PERFMON_PERFSTATE_GUID^PPM_THERMAL_POLICY_CHANGE_GUID^ _RTL_CRITICAL_SECTION_DEBUG05 Type6  CreatorBackTraceIndex7  CriticalSection8%  ProcessLocksList9 EntryCount:  ContentionCount; $ Flags< ( CreatorBackTraceIndexHigh= , SpareWORD> . _RTL_CRITICAL_SECTION(P DebugInfoQ# LockCountR  RecursionCountS  OwningThreadT LockSemaphoreU SpinCountVt  PRTL_CRITICAL_SECTION_DEBUG?# RTL_CRITICAL_SECTIONW CRITICAL_SECTION 2!=!VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN ^VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT ^__mingwthr_cs! y@__mingwthr_cs_init. x@__mingwthr_key_t!!__mingwthr_key >"key! dtor" ,!next#>"!key_dtor_list'#>" x@__mingw_TLScallbackz&@#hDllHandlez.!!reason{" "reserved|#"z&@VF#keyp&>"##t->">$<$&@{&&@& R y@!#=&@=&@~#"$L&@%!#`&@`&@#"$o&@%#]&@&# R y@&@&$__mingwthr_run_key_dtorsc#$%keype>"&%valuem___w64_mingwthr_remove_key_dtorA'p%@$keyA(i$a$prev_keyC>"$$cur_keyD>"J%B%#%@&$ R y@%@{&%@& R y@___w64_mingwthr_add_key_dtor*'$@x%key*%%%dtor*1,!]&O&new_key,%'&#%@&% R1 QH#:%@&% R y@Y%@& R y@!'#$@k{&($^'\')$$@@&($''$@&$@&*$@ R|#$@&_& R y@+$@& R y@,freefree - .-<< p-%- +-xx ,,calloccalloc -cc-VV.4GNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/tlsmcrt.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt$_CRT_MT  @0@int,bGNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/pseudo-reloc-list.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt$__RUNTIME_PSEUDO_RELOC_LIST_END__ Ay@char__RUNTIME_PSEUDO_RELOC_LIST__ @y@\^GNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/crt/pesect.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt&@-%charsize_t(,long long unsigned intlong long intwchar_tgshort unsigned intintlong intpthreadlocinfo(ekthreadlocaleinfostruct`: lc_codepageb lc_collate_cpb lc_handler lc_id $ lc_categoryH lc_clike: mb_cur_max:  lconv_intl_refcount\ lconv_num_refcount\ lconv_mon_refcount\  lconv( ctype1_refcount\0 ctype18 pctype@ pclmapH pcumapP lc_time_currXpthreadmbcinfo%-3 threadmbcinfostruct localeinfo_struct locinfoM mbcinfo_locale_tstructH tagLC_ID wLanguage wCountry wCodePageLC_ID P locale P wlocaleV \ wrefcount \:unsigned intlong unsigned int lconv5unsigned char __lc_time_data_PHNDLRB#:_XCPT_ACTIOND oXcptNumESigNumF :XcptActionG #z_XcptActTabJo_XcptActTabCountK:_XcptActTabSizeL:_First_FPE_IndxM:_Num_FPEN:WINBOOL :BYTEWORDDWORDfloatPBYTE9LPVOIDb__imp__pctype+j__imp__wctype;j__imp__pwctypeGj__newclmapP__newcumapQ__ptlocinfoRM__ptmbcinfoS__globallocalestatusT:__locale_changedU:__initiallocinfoV(k__initiallocalestructinfoW__imp___mb_cur_max\signed charshort intULONG_PTR1.DWORD_PTR'LONGAULONGLONG._GUID4Data1Data2Data3Data44DGUIDDIIDXDVCLSID`DgFMTIDgDzdoublelong doubleP_sys_errlist &_sys_nerr $:__imp___argc \__imp___argv   P__imp___wargv ", 2 V__imp__environ B __imp__wenviron G, __imp__pgmptr N __imp__wpgmptr S2 __imp__osplatform XN__imp__osver ]N__imp__winver bN__imp__winmajor gN__imp__winminor lN_amblksiz 5bGUID_MAX_POWER_SAVINGSQGUID_MIN_POWER_SAVINGSQGUID_TYPICAL_POWER_SAVINGSQNO_SUBGROUP_GUIDQALL_POWERSCHEMES_GUID QGUID_POWERSCHEME_PERSONALITY!QGUID_ACTIVE_POWERSCHEME"QGUID_IDLE_RESILIENCY_SUBGROUP#QGUID_IDLE_RESILIENCY_PERIOD$QGUID_DISK_COALESCING_POWERDOWN_TIMEOUT%QGUID_EXECUTION_REQUIRED_REQUEST_TIMEOUT&QGUID_VIDEO_SUBGROUP'QGUID_VIDEO_POWERDOWN_TIMEOUT(QGUID_VIDEO_ANNOYANCE_TIMEOUT)QGUID_VIDEO_ADAPTIVE_PERCENT_INCREASE*QGUID_VIDEO_DIM_TIMEOUT+QGUID_VIDEO_ADAPTIVE_POWERDOWN,QGUID_MONITOR_POWER_ON-QGUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS.QGUID_DEVICE_POWER_POLICY_VIDEO_DIM_BRIGHTNESS/QGUID_VIDEO_CURRENT_MONITOR_BRIGHTNESS0QGUID_VIDEO_ADAPTIVE_DISPLAY_BRIGHTNESS1QGUID_CONSOLE_DISPLAY_STATE2QGUID_ALLOW_DISPLAY_REQUIRED3QGUID_VIDEO_CONSOLE_LOCK_TIMEOUT4QGUID_ADAPTIVE_POWER_BEHAVIOR_SUBGROUP5QGUID_NON_ADAPTIVE_INPUT_TIMEOUT6QGUID_DISK_SUBGROUP7QGUID_DISK_POWERDOWN_TIMEOUT8QGUID_DISK_IDLE_TIMEOUT9QGUID_DISK_BURST_IGNORE_THRESHOLD:QGUID_DISK_ADAPTIVE_POWERDOWN;QGUID_SLEEP_SUBGROUP<QGUID_SLEEP_IDLE_THRESHOLD=QGUID_STANDBY_TIMEOUT>QGUID_UNATTEND_SLEEP_TIMEOUT?QGUID_HIBERNATE_TIMEOUT@QGUID_HIBERNATE_FASTS4_POLICYAQGUID_CRITICAL_POWER_TRANSITIONBQGUID_SYSTEM_AWAYMODECQGUID_ALLOW_AWAYMODEDQGUID_ALLOW_STANDBY_STATESEQGUID_ALLOW_RTC_WAKEFQGUID_ALLOW_SYSTEM_REQUIREDGQGUID_SYSTEM_BUTTON_SUBGROUPHQGUID_POWERBUTTON_ACTIONIQGUID_SLEEPBUTTON_ACTIONJQGUID_USERINTERFACEBUTTON_ACTIONKQGUID_LIDCLOSE_ACTIONLQGUID_LIDOPEN_POWERSTATEMQGUID_BATTERY_SUBGROUPNQGUID_BATTERY_DISCHARGE_ACTION_0OQGUID_BATTERY_DISCHARGE_LEVEL_0PQGUID_BATTERY_DISCHARGE_FLAGS_0QQGUID_BATTERY_DISCHARGE_ACTION_1RQGUID_BATTERY_DISCHARGE_LEVEL_1SQGUID_BATTERY_DISCHARGE_FLAGS_1TQGUID_BATTERY_DISCHARGE_ACTION_2UQGUID_BATTERY_DISCHARGE_LEVEL_2VQGUID_BATTERY_DISCHARGE_FLAGS_2WQGUID_BATTERY_DISCHARGE_ACTION_3XQGUID_BATTERY_DISCHARGE_LEVEL_3YQGUID_BATTERY_DISCHARGE_FLAGS_3ZQGUID_PROCESSOR_SETTINGS_SUBGROUP[QGUID_PROCESSOR_THROTTLE_POLICY\QGUID_PROCESSOR_THROTTLE_MAXIMUM]QGUID_PROCESSOR_THROTTLE_MINIMUM^QGUID_PROCESSOR_ALLOW_THROTTLING_QGUID_PROCESSOR_IDLESTATE_POLICY`QGUID_PROCESSOR_PERFSTATE_POLICYaQGUID_PROCESSOR_PERF_INCREASE_THRESHOLDbQGUID_PROCESSOR_PERF_DECREASE_THRESHOLDcQGUID_PROCESSOR_PERF_INCREASE_POLICYdQGUID_PROCESSOR_PERF_DECREASE_POLICYeQGUID_PROCESSOR_PERF_INCREASE_TIMEfQGUID_PROCESSOR_PERF_DECREASE_TIMEgQGUID_PROCESSOR_PERF_TIME_CHECKhQGUID_PROCESSOR_PERF_BOOST_POLICYiQGUID_PROCESSOR_PERF_BOOST_MODEjQGUID_PROCESSOR_IDLE_ALLOW_SCALINGkQGUID_PROCESSOR_IDLE_DISABLElQGUID_PROCESSOR_IDLE_STATE_MAXIMUMmQGUID_PROCESSOR_IDLE_TIME_CHECKnQGUID_PROCESSOR_IDLE_DEMOTE_THRESHOLDoQGUID_PROCESSOR_IDLE_PROMOTE_THRESHOLDpQGUID_PROCESSOR_CORE_PARKING_INCREASE_THRESHOLDqQGUID_PROCESSOR_CORE_PARKING_DECREASE_THRESHOLDrQGUID_PROCESSOR_CORE_PARKING_INCREASE_POLICYsQGUID_PROCESSOR_CORE_PARKING_DECREASE_POLICYtQGUID_PROCESSOR_CORE_PARKING_MAX_CORESuQGUID_PROCESSOR_CORE_PARKING_MIN_CORESvQGUID_PROCESSOR_CORE_PARKING_INCREASE_TIMEwQGUID_PROCESSOR_CORE_PARKING_DECREASE_TIMExQGUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_DECREASE_FACTORyQGUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_THRESHOLDzQGUID_PROCESSOR_CORE_PARKING_AFFINITY_WEIGHTING{QGUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_DECREASE_FACTOR|QGUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_THRESHOLD}QGUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_WEIGHTING~QGUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_THRESHOLDQGUID_PROCESSOR_PARKING_CORE_OVERRIDEQGUID_PROCESSOR_PARKING_PERF_STATEQGUID_PROCESSOR_PARKING_CONCURRENCY_THRESHOLDQGUID_PROCESSOR_PARKING_HEADROOM_THRESHOLDQGUID_PROCESSOR_PERF_HISTORYQGUID_PROCESSOR_PERF_LATENCY_HINTQGUID_PROCESSOR_DISTRIBUTE_UTILITYQGUID_SYSTEM_COOLING_POLICYQGUID_LOCK_CONSOLE_ON_WAKEQGUID_DEVICE_IDLE_POLICYQGUID_ACDC_POWER_SOURCEQGUID_LIDSWITCH_STATE_CHANGEQGUID_BATTERY_PERCENTAGE_REMAININGQGUID_GLOBAL_USER_PRESENCEQGUID_SESSION_DISPLAY_STATUSQGUID_SESSION_USER_PRESENCEQGUID_IDLE_BACKGROUND_TASKQGUID_BACKGROUND_TASK_NOTIFICATIONQGUID_APPLAUNCH_BUTTONQGUID_PCIEXPRESS_SETTINGS_SUBGROUPQGUID_PCIEXPRESS_ASPM_POLICYQGUID_ENABLE_SWITCH_FORCED_SHUTDOWNQPPM_PERFSTATE_CHANGE_GUIDQPPM_PERFSTATE_DOMAIN_CHANGE_GUIDQPPM_IDLESTATE_CHANGE_GUIDQPPM_PERFSTATES_DATA_GUIDQPPM_IDLESTATES_DATA_GUIDQPPM_IDLE_ACCOUNTING_GUIDQPPM_IDLE_ACCOUNTING_EX_GUIDQPPM_THERMALCONSTRAINT_GUIDQPPM_PERFMON_PERFSTATE_GUIDQPPM_THERMAL_POLICY_CHANGE_GUIDQW _IMAGE_DOS_HEADER@q e_magicr  e_cblps  e_cpt  e_crlcu  e_cparhdrv  e_minallocw  e_maxallocx  e_ssy  e_spz  e_csum{  e_ip|  e_cs}  e_lfarlc~  e_ovno  e_res  e_oemid $ e_oeminfo & e_res2 ( e_lfanew <   IMAGE_DOS_HEADERWPIMAGE_DOS_HEADER!W _IMAGE_FILE_HEADER! Machine  NumberOfSections   PointerToSymbolTable  NumberOfSymbols  SizeOfOptionalHeader  IMAGE_FILE_HEADER! _IMAGE_DATA_DIRECTORY3"  Size IMAGE_DATA_DIRECTORY !3"a" _IMAGE_OPTIONAL_HEADER64W% MagicX  MajorLinkerVersionY  MinorLinkerVersionZ  SizeOfCode[  SizeOfInitializedData\  SizeOfUninitializedData]  AddressOfEntryPoint^  BaseOfCode_  ImageBase` SectionAlignmenta  FileAlignmentb $ MajorOperatingSystemVersionc ( MinorOperatingSystemVersiond * MajorImageVersione , MinorImageVersionf . MajorSubsystemVersiong 0 MinorSubsystemVersionh 2 Win32VersionValuei 4 SizeOfImagej 8 SizeOfHeadersk < CheckSuml @ Subsystemm D DllCharacteristicsn F SizeOfStackReserveoH SizeOfStackCommitpP SizeOfHeapReserveqX SizeOfHeapCommitr` LoaderFlagss h NumberOfRvaAndSizest l DataDirectoryuQ"pIMAGE_OPTIONAL_HEADER64va"PIMAGE_OPTIONAL_HEADER64v %a"PIMAGE_OPTIONAL_HEADER&%_IMAGE_NT_HEADERS64y& Signature  FileHeader! OptionalHeader%PIMAGE_NT_HEADERS64&&PIMAGE_NT_HEADERS!y&&PhysicalAddressVirtualSize _IMAGE_SECTION_HEADER(' Name G Misc &  SizeOfRawData  PointerToRawData  PointerToRelocations  PointerToLinenumbers  NumberOfRelocations  NumberOfLinenumbers "  $PIMAGE_SECTION_HEADER (&Q(OriginalFirstThunk _IMAGE_IMPORT_DESCRIPTOR((  ForwarderChain  Name  FirstThunk IMAGE_IMPORT_DESCRIPTORQ(PIMAGE_IMPORT_DESCRIPTOR0 )(VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN QVIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT QRPC_IF_HANDLE BIWinTypesBase_v0_1_c_ifspec *k)IWinTypesBase_v0_1_s_ifspec +k)IID_IUnknownaQIID_AsyncIUnknownQIID_IClassFactory8QIID_IMarshalQIID_INoMarshalQIID_IAgileObjectQIID_IAgileReference>QIID_IMarshal2QIID_IMallocQIID_IStdMarshalInfoQIID_IExternalConnectionQIID_IMultiQIbQIID_AsyncIMultiQIQIID_IInternalUnknownQIID_IEnumUnknownbQIID_IEnumStringQIID_ISequentialStreampQIID_IStreamQIID_IRpcChannelBuffer% QIID_IRpcChannelBuffer2 QIID_IAsyncRpcChannelBuffer! QIID_IRpcChannelBuffer3 QIID_IRpcSyntaxNegotiate QIID_IRpcProxyBuffer QIID_IRpcStubBufferI QIID_IPSFactoryBuffer QIID_IChannelHookH QIID_IClientSecurity(QIID_IServerSecurityQIID_IRpcOptions0QIID_IGlobalOptionsQIID_ISurrogateQIID_IGlobalInterfaceTabletQIID_ISynchronizeQIID_ISynchronizeHandleFQIID_ISynchronizeEventQIID_ISynchronizeContainerQIID_ISynchronizeMutexJQIID_ICancelMethodCallsQIID_IAsyncManagerQIID_ICallFactorywQIID_IRpcHelperQIID_IReleaseMarshalBuffers&QIID_IWaitMultiplexQIID_IAddrTrackingControlQIID_IAddrExclusionControl,QIID_IPipeByteQIID_IPipeLongQIID_IPipeDoubleEQIID_IComThreadingInfoQIID_IProcessInitControl1QIID_IFastRundownQIID_IMarshalingStreamQIID_ICallbackWithNoReentrancyToApplicationSTAzQGUID_NULL bCATID_MARSHALERbIID_IRpcChannelbIID_IRpcStubbIID_IStubManagerbIID_IRpcProxybIID_IProxyManagerbIID_IPSFactorybIID_IInternalMonikerbIID_IDfReserved1bIID_IDfReserved2bIID_IDfReserved3bCLSID_StdMarshaluCLSID_AggStdMarshaluCLSID_StdAsyncActManageruIID_IStubbIID_IProxybIID_IEnumGenericbIID_IEnumHolderbIID_IEnumCallback bIID_IOleManager!bIID_IOlePresObj"bIID_IDebug#bIID_IDebugStream$bCLSID_PSGenObject%uCLSID_PSClientSite&uCLSID_PSClassObject'uCLSID_PSInPlaceActive(uCLSID_PSInPlaceFrame)uCLSID_PSDragDrop*uCLSID_PSBindCtx+uCLSID_PSEnumerators,uCLSID_StaticMetafile-uCLSID_StaticDib.uCID_CDfsVolume/uCLSID_DCOMAccessControl0uCLSID_GlobalOptions1uCLSID_StdGlobalInterfaceTable2uCLSID_ComBinding3uCLSID_StdEvent4uCLSID_ManualResetEvent5uCLSID_SynchronizeContainer6uCLSID_AddrControl7uCLSID_CCDFormKrnl8uCLSID_CCDPropertyPage9uCLSID_CCDFormDialog:uCLSID_CCDCommandButton;uCLSID_CCDComboBox<uCLSID_CCDTextBox=uCLSID_CCDCheckBox>uCLSID_CCDLabel?uCLSID_CCDOptionButton@uCLSID_CCDListBoxAuCLSID_CCDScrollBarBuCLSID_CCDGroupBoxCuCLSID_CCDGeneralPropertyPageDuCLSID_CCDGenericPropertyPageEuCLSID_CCDFontPropertyPageFuCLSID_CCDColorPropertyPageGuCLSID_CCDLabelPropertyPageHuCLSID_CCDCheckBoxPropertyPageIuCLSID_CCDTextBoxPropertyPageJuCLSID_CCDOptionButtonPropertyPageKuCLSID_CCDListBoxPropertyPageLuCLSID_CCDCommandButtonPropertyPageMuCLSID_CCDComboBoxPropertyPageNuCLSID_CCDScrollBarPropertyPageOuCLSID_CCDGroupBoxPropertyPagePuCLSID_CCDXObjectPropertyPageQuCLSID_CStdPropertyFrameRuCLSID_CFormPropertyPageSuCLSID_CGridPropertyPageTuCLSID_CWSJArticlePageUuCLSID_CSystemPageVuCLSID_IdentityUnmarshalWuCLSID_InProcFreeMarshalerXuCLSID_Picture_MetafileYuCLSID_Picture_EnhMetafileZuCLSID_Picture_Dib[uGUID_TRISTATE\QIWinTypes_v0_1_c_ifspec)k)IWinTypes_v0_1_s_ifspec*k)IID_IMallocSpyQIID_IBindCtx:QIID_IEnumMonikerJ QIID_IRunnableObject QIID_IRunningObjectTable!QIID_IPersisti"QIID_IPersistStream"QIID_IMonikerj#QIID_IROTDataX%QIID_IEnumSTATSTG%QIID_IStorageX&QIID_IPersistFileA(QIID_IPersistStorage(QIID_ILockBytes)QIID_IEnumFORMATETC*QIID_IEnumSTATDATAl+QIID_IRootStorage,QIID_IAdviseSink,QIID_AsyncIAdviseSinks-QIID_IAdviseSink2.QIID_AsyncIAdviseSink2./QIID_IDataObject/QIID_IDataAdviseHolder1QIID_IMessageFilter1QFMTID_SummaryInformation]2FMTID_DocSummaryInformation_2FMTID_UserDefinedPropertiesa2FMTID_DiscardableInformationc2FMTID_ImageSummaryInformatione2FMTID_AudioSummaryInformationg2FMTID_VideoSummaryInformationi2FMTID_MediaFileSummaryInformationk2IID_IClassActivators2QIID_IFillLockBytes2QIID_IProgressNotify3QIID_ILayoutStorage3QIID_IBlockingLock4QIID_ITimeAndNoticeControl4QIID_IOplockStorageN5QIID_IDirectWriterLock5QIID_IUrlMonM6QIID_IForegroundTransfer6QIID_IThumbnailExtractor7QIID_IDummyHICONIncluder7QIID_IProcessLock7QIID_ISurrogateServiceH8QIID_IInitializeSpy8QIID_IApartmentShutdown9QIID_IOleAdviseHolderQIID_IOleCacheQIID_IOleCache2QIID_IOleCacheControlQIID_IParseDisplayNameQIID_IOleContainerpQIID_IOleClientSiteQIID_IOleObjectQIOLETypes_v0_0_c_ifspeck)IOLETypes_v0_0_s_ifspeck)IID_IOleWindowQIID_IOleLinkkQIID_IOleItemContainer9QIID_IOleInPlaceUIWindowQIID_IOleInPlaceActiveObjectXQIID_IOleInPlaceFrame QIID_IOleInPlaceObject QIID_IOleInPlaceSitef QIID_IContinue, QIID_IViewObject{ QIID_IViewObject2 QIID_IDropSource9 QIID_IDropTarget QIID_IDropSourceNotify0QIID_IEnumOLEVERBQIID_IServiceProviderTQIOleAutomationTypes_v1_0_c_ifspecdk)IOleAutomationTypes_v1_0_s_ifspecek)IID_ICreateTypeInfoQIID_ICreateTypeInfo2 QIID_ICreateTypeLibQIID_ICreateTypeLib2QIID_IDispatchlQIID_IEnumVARIANT QIID_ITypeComp QIID_ITypeInfo] QIID_ITypeInfo2 QIID_ITypeLibQIID_ITypeLib2QIID_ITypeChangeEventsQIID_IErrorInfolQIID_ICreateErrorInfoQIID_ISupportErrorInfodQIID_ITypeFactoryQIID_ITypeMarshalQIID_IRecordInfoQIID_IErrorLogQIID_IPropertyBagQ__MIDL_itf_msxml_0000_v0_0_c_ifspeck)__MIDL_itf_msxml_0000_v0_0_s_ifspeck)LIBID_MSXMLbIID_IXMLDOMImplementationbIID_IXMLDOMNode(bIID_IXMLDOMDocumentFragmentbIID_IXMLDOMDocumentgbIID_IXMLDOMNodeListvbIID_IXMLDOMNamedNodeMapbIID_IXMLDOMCharacterDatabIID_IXMLDOMAttributebIID_IXMLDOMElementbIID_IXMLDOMTextbIID_IXMLDOMComment&bIID_IXMLDOMProcessingInstructionbIID_IXMLDOMCDATASectionbIID_IXMLDOMDocumentTypebIID_IXMLDOMNotation bIID_IXMLDOMEntitybIID_IXMLDOMEntityReferencebIID_IXMLDOMParseErrorb bIID_IXTLRuntime bDIID_XMLDOMDocumentEvents> bCLSID_DOMDocument] uCLSID_DOMFreeThreadedDocumenta uIID_IXMLHttpRequesth bCLSID_XMLHTTPRequest uIID_IXMLDSOControl bCLSID_XMLDSOControl uIID_IXMLElementCollection bIID_IXMLDocumentK bIID_IXMLDocument2 bIID_IXMLElement% bIID_IXMLElement2 bIID_IXMLAttribute bIID_IXMLError bCLSID_XMLDocument/ uCLSID_SBS_StdURLMonikerKbCLSID_SBS_HttpProtocolLbCLSID_SBS_FtpProtocolMbCLSID_SBS_GopherProtocolNbCLSID_SBS_HttpSProtocolObCLSID_SBS_FileProtocolPbCLSID_SBS_MkProtocolQbCLSID_SBS_UrlMkBindCtxRbCLSID_SBS_SoftDistExtSbCLSID_SBS_CdlProtocolTbCLSID_SBS_ClassInstallFilterUbCLSID_SBS_InternetSecurityManagerVbCLSID_SBS_InternetZoneManagerWbIID_IAsyncMoniker`bCLSID_StdURLMonikerabCLSID_HttpProtocolbbCLSID_FtpProtocolcbCLSID_GopherProtocoldbCLSID_HttpSProtocolebCLSID_FileProtocolfbCLSID_MkProtocolgbCLSID_StdURLProtocolhbCLSID_UrlMkBindCtxibCLSID_CdlProtocoljbCLSID_ClassInstallFilterkbIID_IAsyncBindCtxlbIID_IPersistMonikerQIID_IMonikerPropQIID_IBindProtocolQIID_IBindinghQIID_IBindStatusCallbackQIID_IBindStatusCallbackExQIID_IAuthenticateQIID_IAuthenticateExQIID_IHttpNegotiate^QIID_IHttpNegotiate2QIID_IHttpNegotiate3: QIID_IWinInetFileStream QIID_IWindowForBindingUI QIID_ICodeInstallz QIID_IUri QIID_IUriContainer QIID_IUriBuilder QIID_IUriBuilderFactory^QIID_IWinInetInfoQIID_IHttpSecurity6QIID_IWinInetHttpInfoQIID_IWinInetHttpTimeoutsQIID_IWinInetCacheHintsoQIID_IWinInetCacheHints2QSID_BindHost4QIID_IBindHost>QIID_IInternet`QIID_IInternetBindInfoQIID_IInternetBindInfoEx'QIID_IInternetProtocolRootQIID_IInternetProtocolIQIID_IInternetProtocolExQIID_IInternetProtocolSinkQIID_IInternetProtocolSinkStackable1QIID_IInternetSessionQIID_IInternetThreadSwitch\QIID_IInternetPriorityQIID_IInternetProtocolInfoFQCLSID_InternetSecurityManagerwbCLSID_InternetZoneManagerxbCLSID_PersistentZoneIdentifier{bIID_IInternetSecurityMgrSiteQIID_IInternetSecurityManagerQIID_IInternetSecurityManagerExQIID_IInternetSecurityManagerEx2QIID_IZoneIdentifierQIID_IInternetHostSecurityManagerQGUID_CUSTOM_LOCALMACHINEZONEUNLOCKEDXQIID_IInternetZoneManagerQIID_IInternetZoneManagerExQIID_IInternetZoneManagerEx2 QCLSID_SoftDistExt!bIID_ISoftDistExt!QIID_ICatalogFileInfox"QIID_IDataFilter"QIID_IEncodingFilterFactoryp#QGUID_CUSTOM_CONFIRMOBJECTSAFETY#QIID_IWrappedProtocol#QIID_IGetBindHandleR$QIID_IBindCallbackRedirect$QIID_IPropertyStorageQIID_IPropertySetStorageQIID_IEnumSTATPROPSTG*QIID_IEnumSTATPROPSETSTGQIID_StdOlebGUID_DEVINTERFACE_DISK QGUID_DEVINTERFACE_CDROM QGUID_DEVINTERFACE_PARTITIONQGUID_DEVINTERFACE_TAPEQGUID_DEVINTERFACE_WRITEONCEDISKQGUID_DEVINTERFACE_VOLUMEQGUID_DEVINTERFACE_MEDIUMCHANGERQGUID_DEVINTERFACE_FLOPPYQGUID_DEVINTERFACE_CDCHANGERQGUID_DEVINTERFACE_STORAGEPORTQGUID_DEVINTERFACE_COMPORTQGUID_DEVINTERFACE_SERENUM_BUS_ENUMERATORQ_SCARD_IO_REQUESTOUdwProtocol cbPciLength SCARD_IO_REQUEST UOUg_rgSCardT0Pci%.hUg_rgSCardT1Pci%=hUg_rgSCardRawPci%LhUIID_IPrintDialogCallbackQIID_IPrintDialogServicesQ__image_base__ __mingw_enum_import_library_namesiW*@iWi(:'' +&'' importDesc(`(^(' importsStartRVA ((!\*@ W"]#$]$2]$>]%!*@R]&Rr'\6*@6*@?(\))"\)\.)*))\w)q))\))_IsNonwritableInCurrentImagep)@XpTarget%+)) + rvaTarget >*:*'v*t*!\t)@  DX"]# $]$2]$>]%)@R]&Rr*\)@`(\**"\#`)\**)\**)\ ++_GetPEImageBase+@)@(Y +*\D)@ "]#$]$2]$>]%Z)@R]&Rr_FindPESectionExec'(@lYeNo2+.+ +&j+h+'++ b++*\(@ "]#$]$2]$>]%(@R]&Rr__mingw_GetSectionCountp:(@+~Zr +s&*\(@v "]#$]$2]$>]%(@R]&Rr__mingw_GetSectionForAddressb'(@[pb&?++d + rvae ,,*,!\(@ h 3["]# $]$2]$>]%1(@R]&Rr*\?(@`l (\Q,O,"\#`)\v,t,)\,,)\,,_FindPESectionByNameC'p'@\pNameC#iW,,E +F&e-c-G'-- Hb--!\'@O b\"]#$]$2]$>]%'@R]&Rr+'@9^z\&Rs%'@K^&R|&Qs&X8,_FindPESection-'\--+.rva--/&0' 1b,_ValidateImageBaseR]-+/pDOSHeader &/pOptHeader%0\&@]1]R$])2]--)>]--0\'@]1]R)]!..$2]$>]2 '@R]&Rr0\ '@H9^(\H.D.1\Q)\..)\..)\..3strlenstrlen@3strncmpstrncmpVp!GNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/misc/mingw_matherr.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt\+_MINGW_INSTALL_DEBUG_MATHERR P0@int!GNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/stdio/acrt_iob_func.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt+@+charlong long unsigned intlong long intshort unsigned intintlong intunsigned intlong unsigned intunsigned char_iobuf0 _ptr -_cnt _base -_flag _file _charbuf  _bufsiz $_tmpfname -(FILE"i_f__acrt_iob_func &553 __imp___acrt_iob_func `0@ __acrt_iob_func 5+@ index (3// +@ SPl"GNU C99 9.2-win32 20191008 -m64 -mtune=generic -march=x86-64 -g -O2 -std=gnu99 -fno-PIE ./mingw-w64-crt/misc/invalid_parameter_handler.c./build/x86_64-w64-mingw32-x86_64-w64-mingw32-crt+@J,charlong long unsigned intlong long intuintptr_tP,wchar_tg6!short unsigned int6intlong intpthreadlocinfo(|threadlocaleinfostruct`,)Q lc_codepagey lc_collate_cpy lc_handle lc_id $ lc_categoryH lc_clikeQ mb_cur_maxQ  lconv_intl_refcounts lconv_num_refcounts lconv_mon_refcounts  lconv( ctype1_refcounts0 ctype18 pctype@ pclmapH pcumapP lc_time_currXpthreadmbcinfo%DJ threadmbcinfostruct localeinfo_struct locinfod mbcinfo,_locale_tstruct_ tagLC_ID wLanguage6 wCountry6 wCodePage6LC_ID g locale g wlocalem) s wrefcount s!Qunsigned intlong unsigned int lconv6Lunsigned char __lc_time_data_PHNDLRB)/:Q_XCPT_ACTIOND XcptNumESigNumF QXcptActionG :_XcptActTabJ_XcptActTabCountKQ_XcptActTabSizeLQ_First_FPE_IndxMQ_Num_FPENQDWORDfloaty__imp__pctype+9__imp__wctype;9__imp__pwctypeG9wl__newclmapPw__newcumapQw__ptlocinfoRd__ptmbcinfoS,__globallocalestatusTQ__locale_changedUQ__initiallocinfoV(__initiallocalestructinfoW__imp___mb_cur_maxssigned charshort int_GUIDData1Data26Data36Data4GUIDrIIDXCLSID`FMTIDgdoublelong double_invalid_parameter_handlerSYxxxxy1g_sys_errlist&~_sys_nerr$Q__imp___argcs__imp___argvg__imp___wargv"  m__imp__environB__imp__wenvironG __imp__pgmptrN__imp__wpgmptrS __imp__osplatformX__imp__osver]__imp__winverb__imp__winmajorg__imp__winminorl_amblksiz 5yGUID_MAX_POWER_SAVINGS GUID_MIN_POWER_SAVINGS GUID_TYPICAL_POWER_SAVINGS NO_SUBGROUP_GUID ALL_POWERSCHEMES_GUID GUID_POWERSCHEME_PERSONALITY !GUID_ACTIVE_POWERSCHEME "GUID_IDLE_RESILIENCY_SUBGROUP #GUID_IDLE_RESILIENCY_PERIOD $GUID_DISK_COALESCING_POWERDOWN_TIMEOUT %GUID_EXECUTION_REQUIRED_REQUEST_TIMEOUT &GUID_VIDEO_SUBGROUP 'GUID_VIDEO_POWERDOWN_TIMEOUT (GUID_VIDEO_ANNOYANCE_TIMEOUT )GUID_VIDEO_ADAPTIVE_PERCENT_INCREASE *GUID_VIDEO_DIM_TIMEOUT +GUID_VIDEO_ADAPTIVE_POWERDOWN ,GUID_MONITOR_POWER_ON -GUID_DEVICE_POWER_POLICY_VIDEO_BRIGHTNESS .GUID_DEVICE_POWER_POLICY_VIDEO_DIM_BRIGHTNESS /GUID_VIDEO_CURRENT_MONITOR_BRIGHTNESS 0GUID_VIDEO_ADAPTIVE_DISPLAY_BRIGHTNESS 1GUID_CONSOLE_DISPLAY_STATE 2GUID_ALLOW_DISPLAY_REQUIRED 3GUID_VIDEO_CONSOLE_LOCK_TIMEOUT 4GUID_ADAPTIVE_POWER_BEHAVIOR_SUBGROUP 5GUID_NON_ADAPTIVE_INPUT_TIMEOUT 6GUID_DISK_SUBGROUP 7GUID_DISK_POWERDOWN_TIMEOUT 8GUID_DISK_IDLE_TIMEOUT 9GUID_DISK_BURST_IGNORE_THRESHOLD :GUID_DISK_ADAPTIVE_POWERDOWN ;GUID_SLEEP_SUBGROUP <GUID_SLEEP_IDLE_THRESHOLD =GUID_STANDBY_TIMEOUT >GUID_UNATTEND_SLEEP_TIMEOUT ?GUID_HIBERNATE_TIMEOUT @GUID_HIBERNATE_FASTS4_POLICY AGUID_CRITICAL_POWER_TRANSITION BGUID_SYSTEM_AWAYMODE CGUID_ALLOW_AWAYMODE DGUID_ALLOW_STANDBY_STATES EGUID_ALLOW_RTC_WAKE FGUID_ALLOW_SYSTEM_REQUIRED GGUID_SYSTEM_BUTTON_SUBGROUP HGUID_POWERBUTTON_ACTION IGUID_SLEEPBUTTON_ACTION JGUID_USERINTERFACEBUTTON_ACTION KGUID_LIDCLOSE_ACTION LGUID_LIDOPEN_POWERSTATE MGUID_BATTERY_SUBGROUP NGUID_BATTERY_DISCHARGE_ACTION_0 OGUID_BATTERY_DISCHARGE_LEVEL_0 PGUID_BATTERY_DISCHARGE_FLAGS_0 QGUID_BATTERY_DISCHARGE_ACTION_1 RGUID_BATTERY_DISCHARGE_LEVEL_1 SGUID_BATTERY_DISCHARGE_FLAGS_1 TGUID_BATTERY_DISCHARGE_ACTION_2 UGUID_BATTERY_DISCHARGE_LEVEL_2 VGUID_BATTERY_DISCHARGE_FLAGS_2 WGUID_BATTERY_DISCHARGE_ACTION_3 XGUID_BATTERY_DISCHARGE_LEVEL_3 YGUID_BATTERY_DISCHARGE_FLAGS_3 ZGUID_PROCESSOR_SETTINGS_SUBGROUP [GUID_PROCESSOR_THROTTLE_POLICY \GUID_PROCESSOR_THROTTLE_MAXIMUM ]GUID_PROCESSOR_THROTTLE_MINIMUM ^GUID_PROCESSOR_ALLOW_THROTTLING _GUID_PROCESSOR_IDLESTATE_POLICY `GUID_PROCESSOR_PERFSTATE_POLICY aGUID_PROCESSOR_PERF_INCREASE_THRESHOLD bGUID_PROCESSOR_PERF_DECREASE_THRESHOLD cGUID_PROCESSOR_PERF_INCREASE_POLICY dGUID_PROCESSOR_PERF_DECREASE_POLICY eGUID_PROCESSOR_PERF_INCREASE_TIME fGUID_PROCESSOR_PERF_DECREASE_TIME gGUID_PROCESSOR_PERF_TIME_CHECK hGUID_PROCESSOR_PERF_BOOST_POLICY iGUID_PROCESSOR_PERF_BOOST_MODE jGUID_PROCESSOR_IDLE_ALLOW_SCALING kGUID_PROCESSOR_IDLE_DISABLE lGUID_PROCESSOR_IDLE_STATE_MAXIMUM mGUID_PROCESSOR_IDLE_TIME_CHECK nGUID_PROCESSOR_IDLE_DEMOTE_THRESHOLD oGUID_PROCESSOR_IDLE_PROMOTE_THRESHOLD pGUID_PROCESSOR_CORE_PARKING_INCREASE_THRESHOLD qGUID_PROCESSOR_CORE_PARKING_DECREASE_THRESHOLD rGUID_PROCESSOR_CORE_PARKING_INCREASE_POLICY sGUID_PROCESSOR_CORE_PARKING_DECREASE_POLICY tGUID_PROCESSOR_CORE_PARKING_MAX_CORES uGUID_PROCESSOR_CORE_PARKING_MIN_CORES vGUID_PROCESSOR_CORE_PARKING_INCREASE_TIME wGUID_PROCESSOR_CORE_PARKING_DECREASE_TIME xGUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_DECREASE_FACTOR yGUID_PROCESSOR_CORE_PARKING_AFFINITY_HISTORY_THRESHOLD zGUID_PROCESSOR_CORE_PARKING_AFFINITY_WEIGHTING {GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_DECREASE_FACTOR |GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_HISTORY_THRESHOLD }GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_WEIGHTING ~GUID_PROCESSOR_CORE_PARKING_OVER_UTILIZATION_THRESHOLD GUID_PROCESSOR_PARKING_CORE_OVERRIDE GUID_PROCESSOR_PARKING_PERF_STATE GUID_PROCESSOR_PARKING_CONCURRENCY_THRESHOLD GUID_PROCESSOR_PARKING_HEADROOM_THRESHOLD GUID_PROCESSOR_PERF_HISTORY GUID_PROCESSOR_PERF_LATENCY_HINT GUID_PROCESSOR_DISTRIBUTE_UTILITY GUID_SYSTEM_COOLING_POLICY GUID_LOCK_CONSOLE_ON_WAKE GUID_DEVICE_IDLE_POLICY GUID_ACDC_POWER_SOURCE GUID_LIDSWITCH_STATE_CHANGE GUID_BATTERY_PERCENTAGE_REMAINING GUID_GLOBAL_USER_PRESENCE GUID_SESSION_DISPLAY_STATUS GUID_SESSION_USER_PRESENCE GUID_IDLE_BACKGROUND_TASK GUID_BACKGROUND_TASK_NOTIFICATION GUID_APPLAUNCH_BUTTON GUID_PCIEXPRESS_SETTINGS_SUBGROUP GUID_PCIEXPRESS_ASPM_POLICY GUID_ENABLE_SWITCH_FORCED_SHUTDOWN PPM_PERFSTATE_CHANGE_GUID PPM_PERFSTATE_DOMAIN_CHANGE_GUID PPM_IDLESTATE_CHANGE_GUID PPM_PERFSTATES_DATA_GUID PPM_IDLESTATES_DATA_GUID PPM_IDLE_ACCOUNTING_GUID PPM_IDLE_ACCOUNTING_EX_GUID PPM_THERMALCONSTRAINT_GUID PPM_PERFMON_PERFSTATE_GUID PPM_THERMAL_POLICY_CHANGE_GUID VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT RPC_IF_HANDLE BtagCOINITBASEyCOINITBASE_MULTITHREADEDIWinTypesBase_v0_1_c_ifspec *{IWinTypesBase_v0_1_s_ifspec +{IID_IUnknownaIID_AsyncIUnknownIID_IClassFactory8IID_IMarshalIID_INoMarshalIID_IAgileObjectIID_IAgileReference>IID_IMarshal2IID_IMallocIID_IStdMarshalInfoIID_IExternalConnectionIID_IMultiQIbIID_AsyncIMultiQIIID_IInternalUnknownIID_IEnumUnknownbIID_IEnumStringIID_ISequentialStreampIID_IStreamIID_IRpcChannelBuffer% IID_IRpcChannelBuffer2 IID_IAsyncRpcChannelBuffer! IID_IRpcChannelBuffer3 IID_IRpcSyntaxNegotiate IID_IRpcProxyBuffer IID_IRpcStubBufferI IID_IPSFactoryBuffer IID_IChannelHookH IID_IClientSecurity(IID_IServerSecurityIID_IRpcOptions0IID_IGlobalOptionsIID_ISurrogateIID_IGlobalInterfaceTabletIID_ISynchronizeIID_ISynchronizeHandleFIID_ISynchronizeEventIID_ISynchronizeContainerIID_ISynchronizeMutexJIID_ICancelMethodCallsIID_IAsyncManagerIID_ICallFactorywIID_IRpcHelperIID_IReleaseMarshalBuffers&IID_IWaitMultiplexIID_IAddrTrackingControlIID_IAddrExclusionControl,IID_IPipeByteIID_IPipeLongIID_IPipeDoubleEIID_IComThreadingInfoIID_IProcessInitControl1IID_IFastRundownIID_IMarshalingStreamIID_ICallbackWithNoReentrancyToApplicationSTAzGUID_NULL CATID_MARSHALERIID_IRpcChannelIID_IRpcStubIID_IStubManagerIID_IRpcProxyIID_IProxyManagerIID_IPSFactoryIID_IInternalMonikerIID_IDfReserved1IID_IDfReserved2IID_IDfReserved3CLSID_StdMarshalCLSID_AggStdMarshalCLSID_StdAsyncActManagerIID_IStubIID_IProxyIID_IEnumGenericIID_IEnumHolderIID_IEnumCallback IID_IOleManager!IID_IOlePresObj"IID_IDebug#IID_IDebugStream$CLSID_PSGenObject%CLSID_PSClientSite&CLSID_PSClassObject'CLSID_PSInPlaceActive(CLSID_PSInPlaceFrame)CLSID_PSDragDrop*CLSID_PSBindCtx+CLSID_PSEnumerators,CLSID_StaticMetafile-CLSID_StaticDib.CID_CDfsVolume/CLSID_DCOMAccessControl0CLSID_GlobalOptions1CLSID_StdGlobalInterfaceTable2CLSID_ComBinding3CLSID_StdEvent4CLSID_ManualResetEvent5CLSID_SynchronizeContainer6CLSID_AddrControl7CLSID_CCDFormKrnl8CLSID_CCDPropertyPage9CLSID_CCDFormDialog:CLSID_CCDCommandButton;CLSID_CCDComboBox<CLSID_CCDTextBox=CLSID_CCDCheckBox>CLSID_CCDLabel?CLSID_CCDOptionButton@CLSID_CCDListBoxACLSID_CCDScrollBarBCLSID_CCDGroupBoxCCLSID_CCDGeneralPropertyPageDCLSID_CCDGenericPropertyPageECLSID_CCDFontPropertyPageFCLSID_CCDColorPropertyPageGCLSID_CCDLabelPropertyPageHCLSID_CCDCheckBoxPropertyPageICLSID_CCDTextBoxPropertyPageJCLSID_CCDOptionButtonPropertyPageKCLSID_CCDListBoxPropertyPageLCLSID_CCDCommandButtonPropertyPageMCLSID_CCDComboBoxPropertyPageNCLSID_CCDScrollBarPropertyPageOCLSID_CCDGroupBoxPropertyPagePCLSID_CCDXObjectPropertyPageQCLSID_CStdPropertyFrameRCLSID_CFormPropertyPageSCLSID_CGridPropertyPageTCLSID_CWSJArticlePageUCLSID_CSystemPageVCLSID_IdentityUnmarshalWCLSID_InProcFreeMarshalerXCLSID_Picture_MetafileYCLSID_Picture_EnhMetafileZCLSID_Picture_Dib[GUID_TRISTATE\IWinTypes_v0_1_c_ifspec){IWinTypes_v0_1_s_ifspec*{VARENUMy1VT_EMPTYVT_NULLVT_I2VT_I4VT_R4VT_R8VT_CYVT_DATEVT_BSTRVT_DISPATCH VT_ERROR VT_BOOL VT_VARIANT VT_UNKNOWN VT_DECIMALVT_I1VT_UI1VT_UI2VT_UI4VT_I8VT_UI8VT_INTVT_UINTVT_VOIDVT_HRESULTVT_PTRVT_SAFEARRAYVT_CARRAYVT_USERDEFINEDVT_LPSTRVT_LPWSTRVT_RECORD$VT_INT_PTR%VT_UINT_PTR&VT_FILETIME@VT_BLOBAVT_STREAMBVT_STORAGECVT_STREAMED_OBJECTDVT_STORED_OBJECTEVT_BLOB_OBJECTFVT_CFGVT_CLSIDHVT_VERSIONED_STREAMIVT_BSTR_BLOBVT_VECTORVT_ARRAY VT_BYREF@VT_RESERVEDVT_ILLEGALVT_ILLEGALMASKEDVT_TYPEMASKIID_IMallocSpyIID_IBindCtx:IID_IEnumMonikerJ IID_IRunnableObject IID_IRunningObjectTable!IID_IPersisti"IID_IPersistStream"IID_IMonikerj#IID_IROTDataX%IID_IEnumSTATSTG%IID_IStorageX&IID_IPersistFileA(IID_IPersistStorage(IID_ILockBytes)IID_IEnumFORMATETC*IID_IEnumSTATDATAl+IID_IRootStorage,IID_IAdviseSink,IID_AsyncIAdviseSinks-IID_IAdviseSink2.IID_AsyncIAdviseSink2./IID_IDataObject/IID_IDataAdviseHolder1IID_IMessageFilter1FMTID_SummaryInformation]2FMTID_DocSummaryInformation_2FMTID_UserDefinedPropertiesa2FMTID_DiscardableInformationc2FMTID_ImageSummaryInformatione2FMTID_AudioSummaryInformationg2FMTID_VideoSummaryInformationi2FMTID_MediaFileSummaryInformationk2IID_IClassActivators2IID_IFillLockBytes2IID_IProgressNotify3IID_ILayoutStorage3IID_IBlockingLock4IID_ITimeAndNoticeControl4IID_IOplockStorageN5IID_IDirectWriterLock5IID_IUrlMonM6IID_IForegroundTransfer6IID_IThumbnailExtractor7IID_IDummyHICONIncluder7IID_IProcessLock7IID_ISurrogateServiceH8IID_IInitializeSpy8IID_IApartmentShutdown9IID_IOleAdviseHolderIID_IOleCacheIID_IOleCache2IID_IOleCacheControlIID_IParseDisplayNameIID_IOleContainerpIID_IOleClientSiteIID_IOleObjectIOLETypes_v0_0_c_ifspec{IOLETypes_v0_0_s_ifspec{IID_IOleWindowIID_IOleLinkkIID_IOleItemContainer9IID_IOleInPlaceUIWindowIID_IOleInPlaceActiveObjectXIID_IOleInPlaceFrame IID_IOleInPlaceObject IID_IOleInPlaceSitef IID_IContinue, IID_IViewObject{ IID_IViewObject2 IID_IDropSource9 IID_IDropTarget IID_IDropSourceNotify0IID_IEnumOLEVERBIID_IServiceProviderTIOleAutomationTypes_v1_0_c_ifspecd{IOleAutomationTypes_v1_0_s_ifspece{IID_ICreateTypeInfoIID_ICreateTypeInfo2 IID_ICreateTypeLibIID_ICreateTypeLib2IID_IDispatchlIID_IEnumVARIANT IID_ITypeComp IID_ITypeInfo] IID_ITypeInfo2 IID_ITypeLibIID_ITypeLib2IID_ITypeChangeEventsIID_IErrorInfolIID_ICreateErrorInfoIID_ISupportErrorInfodIID_ITypeFactoryIID_ITypeMarshalIID_IRecordInfoIID_IErrorLogIID_IPropertyBag__MIDL_itf_msxml_0000_v0_0_c_ifspec{__MIDL_itf_msxml_0000_v0_0_s_ifspec{LIBID_MSXMLIID_IXMLDOMImplementationIID_IXMLDOMNode(IID_IXMLDOMDocumentFragmentIID_IXMLDOMDocumentgIID_IXMLDOMNodeListvIID_IXMLDOMNamedNodeMapIID_IXMLDOMCharacterDataIID_IXMLDOMAttributeIID_IXMLDOMElementIID_IXMLDOMTextIID_IXMLDOMComment&IID_IXMLDOMProcessingInstructionIID_IXMLDOMCDATASectionIID_IXMLDOMDocumentTypeIID_IXMLDOMNotation IID_IXMLDOMEntityIID_IXMLDOMEntityReferenceIID_IXMLDOMParseErrorb IID_IXTLRuntime DIID_XMLDOMDocumentEvents> CLSID_DOMDocument] CLSID_DOMFreeThreadedDocumenta IID_IXMLHttpRequesth CLSID_XMLHTTPRequest IID_IXMLDSOControl CLSID_XMLDSOControl IID_IXMLElementCollection IID_IXMLDocumentK IID_IXMLDocument2 IID_IXMLElement% IID_IXMLElement2 IID_IXMLAttribute IID_IXMLError CLSID_XMLDocument/ CLSID_SBS_StdURLMonikerKCLSID_SBS_HttpProtocolLCLSID_SBS_FtpProtocolMCLSID_SBS_GopherProtocolNCLSID_SBS_HttpSProtocolOCLSID_SBS_FileProtocolPCLSID_SBS_MkProtocolQCLSID_SBS_UrlMkBindCtxRCLSID_SBS_SoftDistExtSCLSID_SBS_CdlProtocolTCLSID_SBS_ClassInstallFilterUCLSID_SBS_InternetSecurityManagerVCLSID_SBS_InternetZoneManagerWIID_IAsyncMoniker`CLSID_StdURLMonikeraCLSID_HttpProtocolbCLSID_FtpProtocolcCLSID_GopherProtocoldCLSID_HttpSProtocoleCLSID_FileProtocolfCLSID_MkProtocolgCLSID_StdURLProtocolhCLSID_UrlMkBindCtxiCLSID_CdlProtocoljCLSID_ClassInstallFilterkIID_IAsyncBindCtxlIID_IPersistMonikerIID_IMonikerPropIID_IBindProtocolIID_IBindinghIID_IBindStatusCallbackIID_IBindStatusCallbackExIID_IAuthenticateIID_IAuthenticateExIID_IHttpNegotiate^IID_IHttpNegotiate2IID_IHttpNegotiate3: IID_IWinInetFileStream IID_IWindowForBindingUI IID_ICodeInstallz IID_IUri IID_IUriContainer IID_IUriBuilder IID_IUriBuilderFactory^IID_IWinInetInfoIID_IHttpSecurity6IID_IWinInetHttpInfoIID_IWinInetHttpTimeoutsIID_IWinInetCacheHintsoIID_IWinInetCacheHints2SID_BindHost4IID_IBindHost>IID_IInternet`IID_IInternetBindInfoIID_IInternetBindInfoEx'IID_IInternetProtocolRootIID_IInternetProtocolIIID_IInternetProtocolExIID_IInternetProtocolSinkIID_IInternetProtocolSinkStackable1IID_IInternetSessionIID_IInternetThreadSwitch\IID_IInternetPriorityIID_IInternetProtocolInfoFCLSID_InternetSecurityManagerwCLSID_InternetZoneManagerxCLSID_PersistentZoneIdentifier{IID_IInternetSecurityMgrSiteIID_IInternetSecurityManagerIID_IInternetSecurityManagerExIID_IInternetSecurityManagerEx2IID_IZoneIdentifierIID_IInternetHostSecurityManagerGUID_CUSTOM_LOCALMACHINEZONEUNLOCKEDXIID_IInternetZoneManagerIID_IInternetZoneManagerExIID_IInternetZoneManagerEx2 CLSID_SoftDistExt!IID_ISoftDistExt!IID_ICatalogFileInfox"IID_IDataFilter"IID_IEncodingFilterFactoryp#GUID_CUSTOM_CONFIRMOBJECTSAFETY#IID_IWrappedProtocol#IID_IGetBindHandleR$IID_IBindCallbackRedirect$IID_IPropertyStorageIID_IPropertySetStorageIID_IEnumSTATPROPSTG*IID_IEnumSTATPROPSETSTGIID_StdOleGUID_DEVINTERFACE_DISK GUID_DEVINTERFACE_CDROM GUID_DEVINTERFACE_PARTITIONGUID_DEVINTERFACE_TAPEGUID_DEVINTERFACE_WRITEONCEDISKGUID_DEVINTERFACE_VOLUMEGUID_DEVINTERFACE_MEDIUMCHANGERGUID_DEVINTERFACE_FLOPPYGUID_DEVINTERFACE_CDCHANGERGUID_DEVINTERFACE_STORAGEPORTGUID_DEVINTERFACE_COMPORTGUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR_SCARD_IO_REQUEST#NdwProtocol cbPciLength SCARD_IO_REQUESTM#Ng_rgSCardT0Pci%. : ; 9 I&I: ;9 I I : ;9  : ;9 I8 : ;9 I8 : ;9 I8 <  : ;9   : ;9 5II!I/  : ; 9  : ; 9 I8 'I!4: ; 9 I?<   : ;9  I 8 : ;9 I 8'I  : ;9 : ;9 I I 'I '!4: ;9 I?<" : ;9 I 8 #  : ;9 $  : ;9 % : ;9 I & I ' : ;9 ( : ;9 I) I8 *> I: ; 9 +( ,> I: ;9 -(. : ; 9 / : ; 9 I 8 0> I: ; 9 1: ; 9 I2534: ; 9 I?44: ; 9 I54: ; 9 I64: ;9 I?7.?: ;9 'I@B8: ;9 IB91:B;.: ;9 ' <: ;9 I=4: ;9 I> ?.: ;9 'I @.: ; 9 'I@BA4: ; 9 IBB UC1RB X Y W D1RB X YW E1BF41BG1RB UX Y W H1I1RB X YW J 1K1L1MNO.?: ; 9 'I@BP.: ; 9 '@BQ UR41S: ; 9 IT.?: ;9 'I U.?: ;9 'I V.?<n: ;9 W.?<n: ; 9 X.?<n: ; Y.?<n: ; 9 Z.?<n: ;9 % $ > : ; 9 I&I: ;9 I I : ;9  : ;9 I8 : ;9 I8 : ;9 I8 <  : ;9   : ;9 I!I/ 'I : ; 9  : ; 9 I8 !4: ; 9 I?< '4: ;9 I?<> I: ; 9 ( > I: ;9 (4: ; 9 I.?: ; 9 '@BB1 .?: ; 9 '@B!4: ; 9 IB"B1#B$.?<n: ;9 % $ > : ; 9 I&I: ;9 I I : ;9  : ;9 I8 : ;9 I8 : ;9 I8 <  : ;9   : ;9 5II!I/ 'I : ; 9  : ; 9 I8 !4: ; 9 I?< 4: ;9 I?<> I: ; 9 ( > I: ;9 ( : ; 9  : ; 9 I 8 > I: ; 9  : ; 9 I!5"4G: ; 9 % 4: ; 9 I?$ > % $ > : ; 9 I I'I4: ; 9 I?.: ; 9 'I@BB1 .?<n: ; 9 % $ > : ; 9 I&I: ;9 I I : ;9  : ;9 I8 : ;9 I8 : ;9 I8 <  : ;9   : ;9 5II!I/ 'I : ; 9  : ; 9 I8 !4: ; 9 I?< 4: ;9 I?< : ; 9  : ; 9 I 8 > I: ; 9 ( : ; 9 I5.?: ; 9 'I@B% $ > : ; 9 I&I: ;9 I I : ;9  : ;9 I8 : ;9 I8 : ;9 I8 <  : ;9   : ;9 I!I/ 4: ; 9 I?<4: ;9 I?<'I : ; 9  : ; 9 I8 !   : ;9  I 8 : ;9 I 85I : ;9  I : ;9 I  : ;9  : ;9 I !I " : ;9 I 8 #  : ;9 $  : ;9 % : ;9 I & I ' : ; 9 ( : ; 9 I)4: ; 9 I*4: ; 9 I?+.?: ; 9 '@B,: ; 9 IB-4: ; 9 IB.1/B011.?: ; 9 '@B213.?<n: ;9 4.?<n: ; 9 5.?<n: ;9 % 4: ; 9 I?$ > % $ > : ; 9 I&I: ;9 I I : ;9  : ;9 I8 : ;9 I8 : ;9 I8 <  : ;9   : ;9 I!I/ 'I : ; 9  : ; 9 I8 !4: ; 9 I?< '4: ;9 I?<4: ; 9 I?4: ; 9 I.: ; 9 'I@B: ; 9 IB1.?: ; 9 'I@B: ; 9 I .?: ; 9 'I !: ; 9 I"4: ; 9 I#.1@B$1B%41&1RB X Y W '41B(.?<n: ; 9 % $ > : ; 9 I I'I!I/ 4: ; 9 I?% $ > &I4: ; 9 I?< I : ; 9  : ; 9 I8 4: ;9 I?< .?: ;9 'I@B : ; 9 IB 4: ; 9 IB 1 B1.?<n: ; 9 .?<n: ;9 % .?: ; 9 '@B% 4: ; 9 I?$ > % : ; 9 I I$ > &I: ;9 I I : ;9  : ;9 I8 : ;9 I8 : ;9 I8 <  : ;9  : ;9 5II!I/ 'I : ; 9  : ; 9 I8 !4: ; 9 I?< &4: ;9 I?< : ;9  : ;9 I> I: ; 9 ( > I: ;9  (! : ; 9 " : ; 9 I 8 #> I: ; 9 $: ; 9 I%5& : ; 9 '4: ; 9 I(.?: ;9 '@B)4: ;9 I*4: ;9 IB+1RB UX YW ,1- U.41B/4101B112B3 14 1U51RB UX YW 6171X YW 819.: ;9 ' :: ;9 I;4: ;9 I< =.: ; 9 ' >4: ; 9 I?: ; 9 I@.: ; 9 '@BA: ; 9 IBBC.1@BD.?<n: ; 9 E.?<n: ; F.?<n: ;9 G.?<n: ;9 % $ > &I4: ; 9 I?< I : ; 9  : ; 9 I8 4: ;9 I?< : ; 9 I 'I I 4: ; 9 I .?: ; 9 '@B: ; 9 IBB1B: ; 9 I.?<n: ; 9 % 4: ; 9 I?$ > % $ > : ; 9 I&I: ;9 I I : ;9  : ;9 I8 : ;9 I8 : ;9 I8 <  : ;9   : ;9 I!I/ 'I : ; 9  : ; 9 I8 !4: ; 9 I?<   : ;9  I 8 : ;9 I 8  : ;9 : ;9 I I 4: ;9 I?< : ;9 I 8   : ;9    : ;9 ! : ;9 I " I # : ;9 $ : ;9 I%'I&> I: ; 9 '( (> I: ;9 )(*4: ; 9 I+4: ; 9 I?,.?: ; 9 'I@B-: ; 9 IB.4: ; 9 IB/4: ; 9 IB011B2134B516: ; 9 IB7.?<n: ; 9 8.?<n: ; 9 9.?<n: ;9 % $ > : ; 9 I&I5I: ;9 I I : ;9  : ;9 I8 : ;9 I8 : ;9 I8 <  : ;9  : ;9 I!I/ 'I : ; 9  : ; 9 I8 !4: ; 9 I?< 4: ;9 I?<4: ; 9 I.?: ; 9 'I@B: ; 9 IB 4: ; 9 IB11 B!1RB X Y W "41#1$.: ; 9 ' %4: ; 9 I& '.1@B(41B) 1*+B1,.?<n: ;9 -.?<n: ; 9 % 4: ; 9 I?$ > % 4: ; 9 I?$ > % $ > &I: ; 9 I: ;9 I I : ;9  : ;9 I8 : ;9 I8 : ;9 I8 <  : ;9   : ;9 I!I/ 'I : ; 9  : ; 9 I8 !4: ; 9 I?< 4: ;9 I?< : ;9  : ;9 I : ;9 I I8 .?: ; 9 'I@B: ; 9 IB4: ; 9 I4: ; 9 IB 4: ; 9 IB!1RB UX Y W "1# U$41%1&B'1RB X Y W (1B)41B*1RB UX Y W +1,.?: ; 9 'I -: ; 9 I.: ; 9 I/4: ; 9 I0.1@B112B13.?<n: ; 9 % 4: ; 9 I?$ > % $ >  I : ; 9  : ; 9 I8 : ; 9 I'II 4: ; 9 I? .?: ; 9 'I@B : ; 9 IB 1 .?<n: ; 9 % $ > : ; 9 I&I: ;9 I I : ;9  : ;9 I8 : ;9 I8 : ;9 I8 <  : ;9   : ;9 I!I/ 'I : ; 9  : ; 9 I8 !4: ; 9 I?< 5I4: ;9 I?<> I: ; 9 ( > I: ;9 (4: ; 9 I'I4: ; 9 I? 'I!.: ; 9 'I@B".: ; 9 'I@B#: ; 9 I$1RB X Y W %1B&.?: ;9 'I ': ;9 I% $ > 4: ; 9 I?< I: ; 9 I'I4: ; 9 I?.?: ; 9 'I@B% $ > 4: ; 9 I?< I'I4: ; 9 I?.?: ; 9 'I@B ./mingw-w64-crt/crt./debian/tmp/usr/x86_64-w64-mingw32/include./debian/tmp/usr/x86_64-w64-mingw32/include/psdk_inc./mingw-w64-crt/includecrtexe.cwinnt.hintrin-impl.hcorecrt.hlocale.hexcpt.hminwindef.hctype.hbasetsd.hguiddef.hstdlib.hmalloc.hminwinbase.herrhandlingapi.hprocessthreadsapi.hvirtdisk.hrpcdce.hwtypesbase.hunknwnbase.hobjidlbase.hcguid.hwtypes.hcombaseapi.hobjidl.holeidl.hservprov.hoaidl.hmsxml.hurlmon.hpropidl.holeauto.hwinioctl.hwinsmcrd.hwinscard.hcommdlg.hinternal.hcorecrt_startup.hprocess.hmath.htchar.hstring.hsynchapi.hwinbase.h @K {y.gtwB J=~sgiXZ$t]kJ J~ ~K yE "t3A {tK  u. xtw x   u  X ut . . % . .!YY ZZ  GX9.?;t tuJ <Z  KIw!Xi f5tr> t K;KW=T tut`dh dh!j  o] .  ./h  .uJg~ KY Z1 .KY Z1.K )X ./mingw-w64-crt/crt./debian/tmp/usr/x86_64-w64-mingw32/includegccmain.ccorecrt.hexcpt.hminwindef.hctype.hguiddef.hstdlib.hmalloc.hwinnt.hvirtdisk.hrpcdce.hwtypesbase.hunknwnbase.hobjidlbase.hcguid.hwtypes.hcombaseapi.hobjidl.holeidl.hservprov.hoaidl.hmsxml.hurlmon.hpropidl.holeauto.hwinioctl.hwinsmcrd.hwinscard.hcommdlg.h @K   / M q]gBtY]JXt,J]uex+f+X<c ./debian/tmp/usr/x86_64-w64-mingw32/include./mingw-w64-crt/include./mingw-w64-crt/crtcorecrt.hexcpt.hminwindef.hctype.hbasetsd.hwinnt.hguiddef.hstdlib.hmalloc.hminwinbase.hvirtdisk.hrpcdce.hwtypesbase.hunknwnbase.hobjidlbase.hcguid.hwtypes.hcombaseapi.hobjidl.holeidl.hservprov.hoaidl.hmsxml.hurlmon.hpropidl.holeauto.hwinioctl.hwinsmcrd.hwinscard.hcommdlg.hinternal.hnatstart.c;5 ./mingw-w64-crt/crtwildcard.cu ./mingw-w64-crt/crt./debian/tmp/usr/x86_64-w64-mingw32/includecharmax.ccorecrt_startup.h `@ ! ./mingw-w64-crt/crt./debian/tmp/usr/x86_64-w64-mingw32/include./mingw-w64-crt/includedllargv.ccorecrt.hexcpt.hminwindef.hctype.hbasetsd.hwinnt.hguiddef.hstdlib.hmalloc.hminwinbase.hvirtdisk.hrpcdce.hwtypesbase.hunknwnbase.hobjidlbase.hcguid.hwtypes.hobjidl.holeidl.hservprov.hoaidl.hmsxml.hurlmon.hpropidl.holeauto.hwinioctl.hwinsmcrd.hwinscard.hcommdlg.hinternal.h p@`+ ./mingw-w64-crt/crt./debian/tmp/usr/x86_64-w64-mingw32/includegs_support.ccorecrt.hstdlib.hmalloc.hexcpt.hwinnt.hminwindef.hctype.hbasetsd.hguiddef.hvirtdisk.herrhandlingapi.hprocessthreadsapi.hsysinfoapi.hprofileapi.h @2tZ&dȮ ^  f/ h V>h zX  . tY @C ?u u yCtg u/J2' tt.'su$  g=dX*JuD;5 ./mingw-w64-crt/crt_newmode.c ./mingw-w64-crt/crt./debian/tmp/usr/x86_64-w64-mingw32/includetlssup.ccorecrt.hexcpt.hminwindef.hctype.hbasetsd.hwinnt.hguiddef.hstdlib.hmalloc.hvirtdisk.hcorecrt_startup.h `@P,YgtY hZ Xgu t  <Y&*) JX sJ X ;5 ./mingw-w64-crt/crtcinitexe.cr ./mingw-w64-crt/crt./debian/tmp/usr/x86_64-w64-mingw32/includemerr.cmath.hstdio.h 0@ Y"t.fa< uu uu_uY5 ./mingw-w64-crt/crtCRT_fp10.c 0@  3@: ./mingw-w64-crt/crtmingw_helpers.c'\ ./mingw-w64-crt/crt./debian/tmp/usr/x86_64-w64-mingw32/include./mingw-w64-crt/includepseudo-reloc.cvadefs.hcorecrt.hexcpt.hminwindef.hctype.hbasetsd.hwinnt.hguiddef.hstdlib.hmalloc.hminwinbase.hvirtdisk.hrpcdce.hwtypesbase.hunknwnbase.hobjidlbase.hcguid.hwtypes.hcombaseapi.hobjidl.holeidl.hservprov.hoaidl.hmsxml.hurlmon.hpropidl.holeauto.hwinioctl.hwinsmcrd.hwinscard.hcommdlg.hinternal.hmemoryapi.hstdio.herrhandlingapi.h @@>tA?.<f+J.=+W.= u "w<< J#"Y Yd tK=K  f e u- aJ. ufJnX Y.J ~ u~ gf. < L !_K=gw ~45 J[&*)<wX7AD`K= 5N1Jgw ~4 f~p <Z !<J'=  J7!w  ~X egw  ~Xf'(= M(= .=X  IX n ./mingw-w64-crt/crt./debian/tmp/usr/x86_64-w64-mingw32/includeusermatherr.cmath.h @ KtZ  K TY g g g=AuX;5 ./mingw-w64-crt/crtxtxtmode.c4 ./mingw-w64-crt/crt./debian/tmp/usr/x86_64-w64-mingw32/includecrt_handler.ccorecrt.hexcpt.hwinnt.hminwindef.hctype.hbasetsd.hguiddef.hstdlib.hmalloc.herrhandlingapi.hvirtdisk.hrpcdce.hwtypesbase.hunknwnbase.hobjidlbase.hcguid.hwtypes.hcombaseapi.hobjidl.holeidl.hservprov.hoaidl.hmsxml.hurlmon.hpropidl.holeauto.hwinioctl.hwinsmcrd.hwinscard.hcommdlg.hsignal.h  @K.#/tY  Y< tY  u +<<etY  @fu D.XY  m[u l    O CfJZ sX XYfh:s5 <wt=5x<> $=JE='!<=6(><r== w+f XXYg'<z.7B.f-,  YXfX  [u, T]+t>dJ .f`   m[u oF  m[u? A 2 N Q 3& ./mingw-w64-crt/crt./debian/tmp/usr/x86_64-w64-mingw32/includetlsthrd.ccorecrt.hexcpt.hminwindef.hctype.hbasetsd.hwinnt.hguiddef.hstdlib.hmalloc.hminwinbase.hvirtdisk.hsynchapi.hprocessthreadsapi.herrhandlingapi.h $@ t0u 0J Y Jx XuXIuc[Jf r<"XX[/rLhwrsKg /X  t <Yb2Jith v  Ut s> .$1 G 0 [ LYt s*Y fLaXJfJ tf@]f  f Z&t  < KY& ^r  .Y :4 ./mingw-w64-crt/crttlsmcrt.cD> ./mingw-w64-crt/crtpseudo-reloc-list.c+ ./mingw-w64-crt/crt./debian/tmp/usr/x86_64-w64-mingw32/includepesect.ccorecrt.hexcpt.hminwindef.hctype.hbasetsd.hwinnt.hguiddef.hstdlib.hmalloc.hvirtdisk.hrpcdce.hwtypesbase.hunknwnbase.hobjidlbase.hcguid.hwtypes.hobjidl.holeidl.hservprov.hoaidl.hmsxml.hurlmon.hpropidl.holeauto.hwinioctl.hwinsmcrd.hwinscard.hcommdlg.hstring.h &@ C JK -q< tQ J>!JY%I@ t&Y<UI `/yCXiI -tS<0MQ J>!JY%II\  N p<_K t<f!XY%Wj t&YJUIX 4@jK t.MQ LYK x<<tMQ J>!JY%I2 vZzJI T<K~ t~< gK~ t~.f~!%YWY t&Y<UIX 4<<YK~ t~<f~gM~!JY%IN t&Y<UIX <m= XK xJ *tw Y0JB<A; ./mingw-w64-crt/miscmingw_matherr.cs ./mingw-w64-crt/stdio./debian/tmp/usr/x86_64-w64-mingw32/includeacrt_iob_func.cstdio.h +@ Y/X =Xn% ./mingw-w64-crt/misc./debian/tmp/usr/x86_64-w64-mingw32/include/psdk_inc./debian/tmp/usr/x86_64-w64-mingw32/includeinvalid_parameter_handler.cintrin-impl.hcorecrt.hexcpt.hminwindef.hctype.hguiddef.hstdlib.hmalloc.hwinnt.hvirtdisk.hrpcdce.hwtypesbase.hunknwnbase.hobjidlbase.hcguid.hwtypes.hcombaseapi.hobjidl.holeidl.hservprov.hoaidl.hmsxml.hurlmon.hpropidl.holeauto.hwinioctl.hwinsmcrd.hwinscard.hcommdlg.h +@v < ts^9 ./mingw-w64-crt/misc__p__acmdln.c +@  ]8 ./mingw-w64-crt/misc__p__fmode.c ,@  x @,@D0 E R F 0@ID@D|@6BBA A(A0A8GN 8A0A(A ABBK  8A0A(A ABBF @"D0]@"D0] @D0Tx `@:D0u4`@jAAD@@ AAH `@@x `@x p@x lH@BAA A(A0D`m 0A(A AABC s 0A(A AABG ,H`@AAA C x $`@/D0R J NL@AAD@e AAC t AAJ NAA @x <0@AADP  AAB x 0@x $0@@jBADPl0@ BAA A(A0D 0A(A AABE G 0A(A AABK \0@ABB B(B0A8A@AH DH O AABBBBA F x @@AD`|@ @ x , @D0b J R A S A L!@BAA A(A0DP{ 0A(A AABE <"@BD0{ BE b BD V BA x Dh$@kBAA A(DPV(A AABLh$@xAAA D@S  AAAC O  AAAA 4hp%@AD0R AH V AI 4h&@AD0l AF Ax &@'@ '@HLp'@BAA D@}  AABG J AAB(@D0|(@+D0f(@lD0g@)@(D0c$p)@D0o E L$*@D0{ A qx $ +@AD0XAx H +@H +@ x  +@ x  ,@ __p__acmdlnCheckSum__mingw_setusermatherrSizeOfImageBaseOfCodeSetUnhandledExceptionFilter_pei386_runtime_relocator_setargvSectionAlignmentMinorSubsystemVersion_fpresetDataDirectory__mingw_init_ehandlerImageBase__set_app_typeSizeOfCodeMajorLinkerVersion__p__fmodeSizeOfHeapReserve_set_invalid_parameter_handler__getmainargs_amsg_exit_inittermSizeOfStackReserveSizeOfHeapCommitMinorLinkerVersionSizeOfStackCommitSizeOfUninitializedDataAddressOfEntryPointMajorSubsystemVersionSizeOfInitializedDataSizeOfHeadersMajorOperatingSystemVersionGetStartupInfoANumberOfRvaAndSizesExceptionRecordDllCharacteristicsSubsystem__enative_startup_stateMinorImageVersionFileAlignmentMinorOperatingSystemVersionLoaderFlagsWin32VersionValueMajorImageVersion__security_init_cookierefcountrefcount__enative_startup_staterefcount__lconv_init__enative_startup_staterefcountGetCurrentProcessIdSetUnhandledExceptionFilterHighPartExceptionRecordRtlCaptureContextRtlVirtualUnwindTerminateProcessRtlLookupFunctionEntryGetCurrentThreadIdGetSystemTimeAsFileTimeQueryPerformanceCounterUnhandledExceptionFilterGetTickCountrefcountGetCurrentProcessdwReasonrefcounthDllHandlelpreserved__mingw_TLScallback__acrt_iob_func_GetPEImageBaseVirtualProtect__acrt_iob_func__mingw_GetSectionCountsSecInfovfprintf__mingw_GetSectionForAddress__enative_startup_stateGetLastErrorVirtualQueryrefcount__setusermatherr_GetPEImageBaseold_handler_FindPESectionExecRtlAddFunctionTablerefcountContextRecordreset_fpu_FindPESectionByNameExceptionRecord_fpresetInitializeCriticalSectionGetLastErrorTlsGetValuerefcountLeaveCriticalSectionEnterCriticalSectionDeleteCriticalSection_fpresetpSectionTimeDateStamppNTHeaderCharacteristicspImageBaseVirtualAddressiSectionrefcount__iob_funcrefcount (R(9R0Pn000RRx1'n000PPPTT08VV 0 WVV0P0T  p@:S1]1:0:jSjqs1:P:UN{TMW0  PP_gPP&Pp&ppRWPPRW`R`gPRST!P!RYPYPXTX] p t']` v t'`ev p 't'env u 't'nsv u 'p 't'syv u '| 't'P| t'?$R$/R$Q$/Q$X$/X0sRsRRR0sQsQQQ0sXsXXX`sRsR`2`sXsXsSsx`g X@gSXRXRR?S @@ @@  A@ @@ @@P_YQYYYAWY P_RRdsPs|s|s# RR*s }"*-s| }"-6RAKRKWs }"@S@_stXeS@SstSSAXS4_R1_R2_R8_R*S*7sx7AS27427U26R'0'dTRj\pRi\itRt\R\R}\pQiTitQtTQTQ}TpXiSitXtSX$S$6X6BSBRXR}SRG\\RR}\PGVVR`P`}V0R0P[R[\R"R";r;AR;Q;AQ;c;A;d;ARC\CDRD\RR\Rp\2PoPPP .P7NPYgP=0D0 000 0  /0/7 7h0hp 081D000p09R9gRgRRR R R6R6KRKR)Q)gQgQQQ Q Q6Q6KQKQ=X=gXgXXXXX X XX=Y=gYgYYY Y Y6Y6KYKY_1g101 0 .1.606o1ow0w10>VPPP-PKnPwPP202\1g0 00 F0FW\Ww|w\FjPPPT TRRRRRRRHRHTRT`RQQQQQQQHQHTQT`QXXXXXXXHXHTXT`XSRHS!SRgSghRhyS-0--Q-8R8RQhyQ$-R-;P;RRhyRpRURRURUpQTQQTQTPSPS`S78P8T\ <R<XLcRc{< $ &{"{< $ &{"PRP{< $ &{"#P{< $ &{"#VPVcRc{< $ &{"_sQq(QVs0RXRRR PRYP0R\YTR!TX500LRLYR_R_RbZlXb0RSR+S+/RR\0Qq 3R@GRGRGTRTR#< $ &R"PPGd0 R SRR Py@g&`p{zG R}he@Kdg{~&*7&274;>DGQUY_ dknz$+.47A.file_gcrtexe.cj  )Ge pP@0 envpargv argc(@ 3Ycmainret0 ) ;.l_endwE .l_start.l_end atexit  T`zp.text9J.data.bss,.xdatap .pdataT  x ez 0 , `.filepgcygming-crtbegin.c@ ,P .text@.data.bss0.xdatap.pdataT.filegmingw.cmain` .text`$.data.bss0.rdata.xdatax .pdatal  .fileggccmain.cC p.92474U gP__main@ 0.text.data.bss0.xdata.pdatax$ x Oe  z0 0 , @ `.filegnatstart.c.text`.data .bss@ {S p `   5!`.filegwildcard.c.text`.data0.bss@B = .   ?.filegcharmax.c` .text`.data0.bssP.xdata.pdata .CRT$XIC("  k  0 V  0.filegdllargv.c_setargvp .textp.data@.bss`.xdata.pdata < P  0 %c! 0.file.ggs_support.c ` `@'.text.data@.bss`x.xdata .pdata.rdatan |-@ % 0 d H.file@g_newmode.c.text`.data@.bssY  .0   ?.filevgtlssup.c<` K Z0__xd_aX__xd_z`q  .text`.data@.bss.xdata.pdata$ .CRT$XLDH.CRT$XLC@.rdata H.CRT$XDZ`.CRT$XDAX.CRT$XLZP.CRT$XLA8.tls$ZZZ .tls 6 >$8 VP 0W <  .filegcinitexe.c.text0 .data@.bss.CRT$XCZ.CRT$XCA.CRT$XIZ0.CRT$XIAt O _   ?@.filegmerr.c_matherr0  .text0  .data@.bss.rdata@.xdata.pdata J   3   0S ` X.filegCRT_fp10.c_fpreset0  fpreset0  .text0 .data@.bss.xdata.pdata .  . 0B ] 0.filegmingw_helpers.c.text@ .data@.bss  .   D.filegpseudo-reloc.c}@    the_secs  `p.text@ e%.data@.bss.rdata.xdata4.pdata$  T` @ v   0  + 0.file(gusermatherr.c5 K Y .text\.data@.bss .xdata, .pdata,T( x  MP 0  @P.file:gxtxtmode.c.text.data@.bss0+ . .   ?.file_gcrt_handler.cp  H`` .textp.data@.bss@.xdata8 .rdataX.pdataD$ , aZ\ b  08 8  .filegtlsthrd.c   3Fp f .text`%.data@.bssH.xdataX,.pdatah0 n &S v! 0p! 7<@ h .filegtlsmcrt.c.text.data@.bss@ ` 4 .  $ >`.filegz.text.dataP.bss@ ; 0b .   $ H.filegpesect.c    p    '@ 7p T .text .dataP.bssP .xdataH.pdataxk `^ '\@ 0-% /] .filegmingw_matherr.c.text.dataP.bssP  p! .p  \+ E.text.data`.bssP .idata$7\.idata$5\.idata$4.idata$6~.text.data`.bssP .idata$7X.idata$5T.idata$4.idata$6t.text.data`.bssP .idata$7T.idata$5L.idata$4.idata$6j.text.data`.bssP .idata$7P.idata$5D.idata$4.idata$6`.text .data`.bssP .idata$7L.idata$5<.idata$4.idata$6X.text(.data`.bssP .idata$7H.idata$54.idata$4.idata$6N.text0.data`.bssP .idata$7D.idata$5,.idata$4.idata$6D.text8.data`.bssP .idata$7@.idata$5$.idata$4.idata$6:.text@.data`.bssP .idata$7<.idata$5.idata$4.idata$62.textH.data`.bssP .idata$78.idata$5.idata$4|.idata$6(.textP.data`.bssP .idata$74.idata$5 .idata$4t.idata$6 .textX.data`.bssP .idata$70.idata$5.idata$4l.idata$6.text`.data`.bssP .idata$7,.idata$5.idata$4d.idata$6.texth.data`.bssP .idata$7(.idata$5.idata$4\.idata$6.textp.data`.bssP .idata$7$.idata$5.idata$4T.idata$6.textx.data`.bssP .idata$7.idata$5.idata$4D.idata$6.text.data`.bssP .idata$7.idata$5.idata$4<.idata$6.text.data`.bssP .idata$7.idata$5.idata$4,.idata$6.text.data`.bssP .idata$7 .idata$5.idata$4$.idata$6.text.data`.bssP .idata$7.idata$5.idata$4.idata$6.text.data`.bssP .idata$7.idata$5.idata$4 .idata$6|.text.data`.bssP .idata$7.idata$5.idata$4.idata$6l.text.data`.bssP .idata$7.idata$5.idata$4.idata$6T.filegacrt_iob_func.cv .text.data`.bssP .xdata.pdata   ! /O 0+    @.fileg  handlerP    .text.datap.bssP .xdata.pdata Pl" :f/S 0J, r)   H H.fileg__p__acmdln.c(  4 .text .data.bss` .xdata.pdata4 j d$  0. b@  0.fileg__p__fmode.cQ  \ .text .data.bss` .xdata.pdata@ }k K(% s  0/ a`  0.filegfakehnamefthunk.text.data.bss` .idata$2.idata$4.idata$5.text.data.bss` .idata$7.idata$5.idata$44.idata$6.text.data.bss` .idata$7.idata$5.idata$4.idata$6.filegfake.text .data.bss` .idata$4.idata$5d.idata$7` .text .data.bss` .idata$7.idata$5.idata$4.idata$6D.text(.data.bss` .idata$7.idata$5|.idata$4.idata$62.text0.data.bss` .idata$7.idata$5t.idata$4.idata$6.text8.data.bss` .idata$7.idata$5l.idata$4.idata$6.text@.data.bss` .idata$7.idata$5d.idata$4.idata$6.textH.data.bss` .idata$7.idata$5\.idata$4.idata$6.textP.data.bss` .idata$7.idata$5T.idata$4.idata$6.textX.data.bss` .idata$7.idata$5L.idata$4.idata$6.text`.data.bss` .idata$7.idata$5D.idata$4.idata$6.texth.data.bss` .idata$7.idata$5<.idata$4.idata$6.textp.data.bss` .idata$7.idata$54.idata$4.idata$6v.textx.data.bss` .idata$7.idata$5,.idata$4.idata$6\.text.data.bss` .idata$7.idata$5$.idata$4.idata$6D.text.data.bss` .idata$7.idata$5.idata$4.idata$6(.text.data.bss` .idata$7.idata$5.idata$4|.idata$6.text.data.bss` .idata$7.idata$5 .idata$4t.idata$6.text.data.bss` .idata$7.idata$5.idata$4l.idata$6.text.data.bss` .idata$7.idata$5.idata$4d.idata$6.text.data.bss` .idata$7.idata$5.idata$4\.idata$6.text.data.bss` .idata$7.idata$5.idata$4T.idata$6.text.data.bss` .idata$7.idata$5.idata$4L.idata$6.text.data.bss` .idata$7.idata$5.idata$4D.idata$6.text.data.bss` .idata$7.idata$5.idata$4<.idata$6l.filegfakehname<fthunk.text.data.bss` .idata$2.idata$4<.idata$5.filegfake.text.data.bss` .idata$4.idata$5.idata$7 .text.data.bss` .idata$7 .idata$5.idata$4L.idata$6.filegcygming-crtend.cx  .text.data.bss`    L  __xc_z    " 1 @ M Ld P     @__xl_a8    _cexitx ( G _ x       8 __xl_dH x_tls_end 0 PF S e z  8  memcpy(  `  pputs   p @( A malloc0 ` _CRT_MT@t 8 @    `  @3>D[(jyX$(abort` `AX__dll__Qf P< @0h$callocX /@90RPdlp4}fprintfH 4SleepH$+ __xi_z07Wd |psignal p  strncmp ':dQ`n}D,L, `:Mmz  \t__xl_zP__end__ T=TbpX__xi_a \__xc_a X_fmode0) 4Qlcu |__xl_c@ x@% =_newmodeTp fwrite8 ^TlP`x h "_onexith 5exitP Gpl_charmax0strlen 0@&<>`xXvfprintf free@ .debug_aranges.debug_info.debug_abbrev.debug_line.debug_frame.debug_str.debug_loc.debug_ranges__mingw_invalidParameterHandlerpre_c_init.rdata$.refptr.mingw_initltsdrot_force.rdata$.refptr.mingw_initltsdyn_force.rdata$.refptr.mingw_initltssuo_force.rdata$.refptr.mingw_initcharmax.rdata$.refptr.__image_base__.rdata$.refptr.mingw_app_typemanagedapp.rdata$.refptr._fmode.rdata$.refptr._MINGW_INSTALL_DEBUG_MATHERRpre_cpp_init.rdata$.refptr._newmodestartinfo.rdata$.refptr._dowildcard__tmainCRTStartup.rdata$.refptr.__native_startup_lock.rdata$.refptr.__native_startup_statehas_cctor.rdata$.refptr.__dyn_tls_init_callback.rdata$.refptr.__mingw_oldexcpt_handler.rdata$.refptr.__imp___initenv.rdata$.refptr.__xc_z.rdata$.refptr.__xc_a.rdata$.refptr.__xi_z.rdata$.refptr.__xi_aWinMainCRTStartup.l_startwmainCRTStartup.rdata$.refptr._gnu_exception_handler.rdata$.refptr._matherr.CRT$XCAA.CRT$XIAA.debug_info.debug_abbrev.debug_loc.debug_aranges.debug_ranges.debug_line.debug_str.rdata$zzz.debug_frame__gcc_register_frame__gcc_deregister_frame__do_global_dtors__do_global_ctors.rdata$.refptr.__CTOR_LIST__initializedmy_lconv_init__security_init_cookie.data$__security_cookie.data$__security_cookie_complement__report_gsfailureGS_ContextRecordGS_ExceptionRecordGS_ExceptionPointers__dyn_tls_dtor__dyn_tls_init.rdata$.refptr._CRT_MT__tlregdtor__report_error__write_memory.part.0maxSections_pei386_runtime_relocatorwas_init.93800.rdata$.refptr.__RUNTIME_PSEUDO_RELOC_LIST_END__.rdata$.refptr.__RUNTIME_PSEUDO_RELOC_LIST____mingw_raise_matherrstUserMathErr__mingw_setusermatherr__mingw_SEH_error_handler__mingw_init_ehandlerwas_here.93644emu_pdataemu_xdata_gnu_exception_handler__mingwthr_run_key_dtors.part.0__mingwthr_cskey_dtor_list___w64_mingwthr_add_key_dtor__mingwthr_cs_init___w64_mingwthr_remove_key_dtor__mingw_TLScallbackpseudo-reloc-list.c_ValidateImageBase.part.0_ValidateImageBase_FindPESection_FindPESectionByName__mingw_GetSectionForAddress__mingw_GetSectionCount_FindPESectionExec_GetPEImageBase_IsNonwritableInCurrentImage__mingw_enum_import_library_names__acrt_iob_funcmingw_get_invalid_parameter_handler_get_invalid_parameter_handlermingw_set_invalid_parameter_handler_set_invalid_parameter_handlerinvalid_parameter_handler.c__p__acmdln.rdata$.refptr.__imp__acmdln__p__fmode.rdata$.refptr.__imp__fmoderegister_frame_ctor.text.startup.xdata.startup.pdata.startup.ctors.65535___RUNTIME_PSEUDO_RELOC_LIST____imp_GetStartupInfoA__imp_abort__lib64_libkernel32_a_iname__data_start_____DTOR_LIST____imp__fmode__imp_RtlVirtualUnwindSetUnhandledExceptionFilter__imp_calloc__imp___p__fmode___tls_start__.refptr.__native_startup_state__ImageBaseGetLastErrorGetSystemTimeAsFileTimemingw_initltssuo_force__rt_psrelocs_start.refptr.mingw_initltsdyn_force__dll_characteristics____size_of_stack_commit____mingw_module_is_dll__iob_func__imp__acmdln__size_of_stack_reserve____major_subsystem_version_____crt_xl_start____imp_DeleteCriticalSection__imp__set_invalid_parameter_handler.refptr.__CTOR_LIST__VirtualQuery___crt_xi_start__.refptr.__imp__fmode__imp__amsg_exit___crt_xi_end__.refptr.__imp___initenv_tls_start__mingw_winmain_lpCmdLine.refptr._matherr.refptr.__RUNTIME_PSEUDO_RELOC_LIST____mingw_oldexcpt_handler__imp_GetCurrentThreadId.refptr.mingw_initltssuo_forceGetCurrentProcessIdTlsGetValueTerminateProcess__bss_start____imp___C_specific_handler___RUNTIME_PSEUDO_RELOC_LIST_END__RtlLookupFunctionEntry__size_of_heap_commit____imp_GetLastError.refptr._dowildcard__imp_free__imp_RtlLookupFunctionEntryVirtualProtectmingw_app_type___crt_xp_start____imp_LeaveCriticalSection__mingw_pinit__C_specific_handler.refptr.mingw_initcharmax__imp_GetTickCount.refptr.__mingw_oldexcpt_handler.refptr.__RUNTIME_PSEUDO_RELOC_LIST_END_____crt_xp_end____minor_os_version____imp_GetSystemTimeAsFileTimeEnterCriticalSection_MINGW_INSTALL_DEBUG_MATHERR__imp_puts.refptr.__xi_a__image_base__.refptr._CRT_MTRtlCaptureContext__section_alignment____native_dllmain_reason_tls_usedUnhandledExceptionFiltermingw_initcharmax__IAT_end____imp_memcpy__RUNTIME_PSEUDO_RELOC_LIST____imp_RtlAddFunctionTable.refptr._newmodemingw_pcppinit__data_end____imp_fwrite__CTOR_LIST____imp___getmainargs_head_lib64_libkernel32_a__bss_end__.refptr.mingw_initltsdrot_forceGetTickCount__native_vcclrit_reason___crt_xc_end__RtlAddFunctionTable.refptr.__native_startup_lock__imp_EnterCriticalSection_tls_index__native_startup_state___crt_xc_start____imp_GetCurrentProcessId__imp___lconv_init__imp_TerminateProcess__lib64_libmsvcrt_os_a_iname___CTOR_LIST__.refptr.__dyn_tls_init_callback__imp_signal__rt_psrelocs_size__imp_QueryPerformanceCounter__imp_strlen__imp_malloc__mingw_winmain_nShowCmdmingw_pcinit.refptr._gnu_exception_handler__file_alignment____imp_InitializeCriticalSection__lconv_init__getmainargsInitializeCriticalSection__imp_exit__imp_vfprintf__major_os_version____imp___initenv__IAT_start____imp__cexit__imp_UnhandledExceptionFilter__imp_SetUnhandledExceptionFilter.refptr.mingw_app_type__imp__onexit__DTOR_LIST__RtlVirtualUnwind.refptr.__imp__acmdln__set_app_type__imp_Sleep__imp___p__acmdlnLeaveCriticalSection__imp___setusermatherr__size_of_heap_reserve_____crt_xt_start____subsystem___amsg_exit__security_cookie_complement__imp_TlsGetValueGetCurrentProcess__setusermatherr__imp_fprintf__imp_VirtualProtect___tls_end__QueryPerformanceCounter__imp_VirtualQuery__imp__inittermmingw_initltsdyn_force_dowildcard__imp___iob_func__dyn_tls_init_callback.refptr.__image_base___initterm__imp_strncmp_head_lib64_libmsvcrt_os_a.refptr._fmode__imp___acrt_iob_func__major_image_version____loader_flags_____chkstk_ms__native_startup_lock__mingw_winmain_hInstanceGetStartupInfoAGetCurrentThreadId__rt_psrelocs_end__imp__get_invalid_parameter_handler__minor_subsystem_version____minor_image_version____imp___set_app_typemingw_initltsdrot_force.refptr.__xc_a.refptr.__xi_z.refptr._MINGW_INSTALL_DEBUG_MATHERRDeleteCriticalSection__imp_RtlCaptureContext__RUNTIME_PSEUDO_RELOC_LIST_END____imp_GetCurrentProcess.refptr.__xc_z___crt_xt_end____security_cookieyara-4.5.3/tests/data/test-pb.data000066400000000000000000000011151501365277300167520ustar00rootroot00000000000000# # Data used by test-pb.c. # # The structure for this data is defined in: # libyara/modules/pb_tests/pb_tests.proto # # Use the command below for encoding the data in binary form: # protoc -I./libyara/pb -I./libyara/modules/pb_tests --encode=test.RootMessage \ # libyara/modules/pb_tests/pb_tests.proto < tests/data/test-pb.data > tests/data/test-pb.data.bin # f_int32: 1111 f_int64: 2222 f_string: "foo" f_struct_array: [ { f_string: "bar" f_enum: 1 }, { f_string: "baz" f_nested_struct: { f_int32: 3333 } } ] yara-4.5.3/tests/data/test-pb.data.bin000066400000000000000000000000401501365277300175150ustar00rootroot00000000000000bfoor barr bazyara-4.5.3/tests/data/tiny000066400000000000000000001000001501365277300154400ustar00rootroot00000000000000MZ@ !L!This program cannot be run in DOS mode. $PELVV  p0@ܨ `a.textt `P`.data000@0.rdataP@@@0@.bssP`.idata`P@0.CRT4p`@0.tls p@0Í&'1f=@MZS@S@S@$P@thP@S@tJ$$ S@S@S@a@=0@tm1Í&$`f<@@PE@uQf t?f j]1Kv$@1Ãyt,1f,S@D$P@D$P@D$P@$P@P@ P@D$ ,fU1WVUS׃|0)čD$@@@ @@@@̃5S@d1X=@a@9$׃S@uޡS@1ۃS@MP@S@,@@tD$D$$Ѓ b $@ vU,0@t<$@@a@tD$@@$ a@…t $,0@$`@Í&U]ÐUu*ÐffffffS(S@$D$$*S@$YD$S@$HD$D$D$D$D$D$0$$ËD$$*S@D$$$S@d([ÐD$0$a@([Í&'D$ $1Ð0@t fС0@P@0@u Ít&S`'@t!t `'@u$p@[1ÍC`'@uɍv'P@tÐt&P@딐%ha@1ÐUWVS,$0@D$D$=N@tУ(0@,[^_]ÍD$$(a@\$3\$a@a@,a@ƍD$$8a@3\$3\$111N@tЉ5$0@(0@,[^_]ÐDO@t&U( S@ EU$S@$Q@P@,S@EP@$0@E(0@EH)ЉẺiËŋE)ljẺN>뮋 S@AD$A@$A@D$D$$A@US]=wK==D$$ t-$ c'=t)==tWS@t=]]t&D$$pt$и]v'D$$0uD$$~=jD$$tXI$|fD$$a&D$$ A&D$$!UWVS$S@a@S@-Ha@=a@t(v$Ճׅu tC4$Ћ[u$S@4a@[^_]ÍvS@uÍSD$ $tBD$ $S@D$$Ca@S@S@$S@C4a@1[ø'SS@\$ u1[Ð&$S@a@S@t9u N9t(‹Bu$S@4a@1[Ð&HJ$&$S@4a@ыBS@ڍt&SD$$ru S@[ÐS@S@uޡS@tX$ۉuS@S@$S@a@랉'S@tS@[Ív$S@0a@Yt&c@<8PEt1ffx ÍvD$f8MZt1f΍&'VST$ \$R<rBDt1ɐP 9wP9r (9u1[^ÍvUWVS|$0<$i1҃w f=@MZt [^_]Ð@Ft<@@@h\t1 (9t&D$|$$uރډ[^_]f1[^_]Ít&1f=@MZtVS@tJ<@\$ @@@rDt"1ɍP 9rP9r(9u1ɉ[^Ð[^É'1f=@MZtÐ@Ft<@@Ðt&V1f=@MZSL$ t [^Ð&@t<@@@ZDt1f@' tt(9u1[^fƉ[^É'1f=@MZtø@@EЉÉ'1f=@MZtfVS@dtJ<@\$ @@@rDt 1ɍP 9rP9r(9u1[^f@$[^t&WV1f=@MZS\$t [^_Í@t<@@@tyQTtJ 9rJ9r(9u1[^_@u t&HuP tׅp [@^_ÐQP=L$ r -=w) XYÐ%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%|a@%xa@%pa@%la@%`a@%\a@ffffffS@Ív'D$S@ÐU]P'@ p'@0'@@'@N@Dlibgcj-16.dll_Jv_RegisterClasses S@@P@@Unknown error_matherr(): %s in %s(%g, %g) (retval=%g) Argument domain error (DOMAIN)Argument singularity (SIGN)Overflow range error (OVERFLOW)The result is too small to be represented (UNDERFLOW)Total loss of significance (TLOSS)Partial loss of significance (PLOSS)l@@@@@@@@A@$A@Mingw-w64 runtime failure: Address %p has no image-section VirtualQuery failed for %d bytes at address %p VirtualProtect failed with code 0x%x Unknown pseudo relocation protocol version %d. Unknown pseudo relocation bit size %d. GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205<`ea`e\aaaab&bdFdPdXdbdldvddddddaaab&bdFdPdXdbdldvddddddDeleteCriticalSectionEnterCriticalSectionGetCurrentProcessGetCurrentProcessIdGetCurrentThreadIdGetLastErrorGetModuleHandleAEGetProcAddressdGetStartupInfoA{GetSystemTimeAsFileTimeGetTickCountInitializeCriticalSection&LeaveCriticalSectionQueryPerformanceCountergSetUnhandledExceptionFiltertSleepTerminateProcessTlsGetValueUnhandledExceptionFilterVirtualProtectVirtualQuery7__dllonexit:__getmainargs;__initenvD__lconv_inith__set_app_typek__setusermatherry_acmdln_amsg_exit_cexit_fmode0_initterm4_iob_lock2_onexitFcallocPexit`fprintfgfreerfwritemallocmemcpysignalstrlenstrncmp_unlock;abortWvfprintf`````````````````````KERNEL32.dll```````````````````````````msvcrt.dll0@@@@p@@@S@ p@yara-4.5.3/tests/data/tiny-idata-51ff000066400000000000000000001000001501365277300172570ustar00rootroot00000000000000MZ@ !L!This program cannot be run in DOS mode. $PELVV  p0@ܨ `a.textt `P`.data000@0.rdataP@@@0@.bssP`.idata`Q@0.CRT4p`@0.tls p@0Í&'1f=@MZS@S@S@$P@thP@S@tJ$$ S@S@S@a@=0@tm1Í&$`f<@@PE@uQf t?f j]1Kv$@1Ãyt,1f,S@D$P@D$P@D$P@$P@P@ P@D$ ,fU1WVUS׃|0)čD$@@@ @@@@̃5S@d1X=@a@9$׃S@uޡS@1ۃS@MP@S@,@@tD$D$$Ѓ b $@ vU,0@t<$@@a@tD$@@$ a@…t $,0@$`@Í&U]ÐUu*ÐffffffS(S@$D$$*S@$YD$S@$HD$D$D$D$D$D$0$$ËD$$*S@D$$$S@d([ÐD$0$a@([Í&'D$ $1Ð0@t fС0@P@0@u Ít&S`'@t!t `'@u$p@[1ÍC`'@uɍv'P@tÐt&P@딐%ha@1ÐUWVS,$0@D$D$=N@tУ(0@,[^_]ÍD$$(a@\$3\$a@a@,a@ƍD$$8a@3\$3\$111N@tЉ5$0@(0@,[^_]ÐDO@t&U( S@ EU$S@$Q@P@,S@EP@$0@E(0@EH)ЉẺiËŋE)ljẺN>뮋 S@AD$A@$A@D$D$$A@US]=wK==D$$ t-$ c'=t)==tWS@t=]]t&D$$pt$и]v'D$$0uD$$~=jD$$tXI$|fD$$a&D$$ A&D$$!UWVS$S@a@S@-Ha@=a@t(v$Ճׅu tC4$Ћ[u$S@4a@[^_]ÍvS@uÍSD$ $tBD$ $S@D$$Ca@S@S@$S@C4a@1[ø'SS@\$ u1[Ð&$S@a@S@t9u N9t(‹Bu$S@4a@1[Ð&HJ$&$S@4a@ыBS@ڍt&SD$$ru S@[ÐS@S@uޡS@tX$ۉuS@S@$S@a@랉'S@tS@[Ív$S@0a@Yt&c@<8PEt1ffx ÍvD$f8MZt1f΍&'VST$ \$R<rBDt1ɐP 9wP9r (9u1[^ÍvUWVS|$0<$i1҃w f=@MZt [^_]Ð@Ft<@@@h\t1 (9t&D$|$$uރډ[^_]f1[^_]Ít&1f=@MZtVS@tJ<@\$ @@@rDt"1ɍP 9rP9r(9u1ɉ[^Ð[^É'1f=@MZtÐ@Ft<@@Ðt&V1f=@MZSL$ t [^Ð&@t<@@@ZDt1f@' tt(9u1[^fƉ[^É'1f=@MZtø@@EЉÉ'1f=@MZtfVS@dtJ<@\$ @@@rDt 1ɍP 9rP9r(9u1[^f@$[^t&WV1f=@MZS\$t [^_Í@t<@@@tyQTtJ 9rJ9r(9u1[^_@u t&HuP tׅp [@^_ÐQP=L$ r -=w) XYÐ%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%|a@%xa@%pa@%la@%`a@%\a@ffffffS@Ív'D$S@ÐU]P'@ p'@0'@@'@N@Dlibgcj-16.dll_Jv_RegisterClasses S@@P@@Unknown error_matherr(): %s in %s(%g, %g) (retval=%g) Argument domain error (DOMAIN)Argument singularity (SIGN)Overflow range error (OVERFLOW)The result is too small to be represented (UNDERFLOW)Total loss of significance (TLOSS)Partial loss of significance (PLOSS)l@@@@@@@@A@$A@Mingw-w64 runtime failure: Address %p has no image-section VirtualQuery failed for %d bytes at address %p VirtualProtect failed with code 0x%x Unknown pseudo relocation protocol version %d. Unknown pseudo relocation bit size %d. GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205<`ea`e\aaaab&bdFdPdXdbdldvddddddaaab&bdFdPdXdbdldvddddddDeleteCriticalSectionEnterCriticalSectionGetCurrentProcessGetCurrentProcessIdGetCurrentThreadIdGetLastErrorGetModuleHandleAEGetProcAddressdGetStartupInfoA{GetSystemTimeAsFileTimeGetTickCountInitializeCriticalSection&LeaveCriticalSectionQueryPerformanceCountergSetUnhandledExceptionFiltertSleepTerminateProcessTlsGetValueUnhandledExceptionFilterVirtualProtectVirtualQuery7__dllonexit:__getmainargs;__initenvD__lconv_inith__set_app_typek__setusermatherry_acmdln_amsg_exit_cexit_fmode0_initterm4_iob_lock2_onexitFcallocPexit`fprintfgfreerfwritemallocmemcpysignalstrlenstrncmp_unlock;abortWvfprintf`````````````````````KERNEL32.dll```````````````````````````msvcrt.dll0@@@@p@@@S@ p@yara-4.5.3/tests/data/tiny-idata-5200000066400000000000000000001000001501365277300171040ustar00rootroot00000000000000MZ@ !L!This program cannot be run in DOS mode. $PELVV  p0@ܨ `a.textt `P`.data000@0.rdataP@@@0@.bssP`.idata`R@0.CRT4p`@0.tls p@0Í&'1f=@MZS@S@S@$P@thP@S@tJ$$ S@S@S@a@=0@tm1Í&$`f<@@PE@uQf t?f j]1Kv$@1Ãyt,1f,S@D$P@D$P@D$P@$P@P@ P@D$ ,fU1WVUS׃|0)čD$@@@ @@@@̃5S@d1X=@a@9$׃S@uޡS@1ۃS@MP@S@,@@tD$D$$Ѓ b $@ vU,0@t<$@@a@tD$@@$ a@…t $,0@$`@Í&U]ÐUu*ÐffffffS(S@$D$$*S@$YD$S@$HD$D$D$D$D$D$0$$ËD$$*S@D$$$S@d([ÐD$0$a@([Í&'D$ $1Ð0@t fС0@P@0@u Ít&S`'@t!t `'@u$p@[1ÍC`'@uɍv'P@tÐt&P@딐%ha@1ÐUWVS,$0@D$D$=N@tУ(0@,[^_]ÍD$$(a@\$3\$a@a@,a@ƍD$$8a@3\$3\$111N@tЉ5$0@(0@,[^_]ÐDO@t&U( S@ EU$S@$Q@P@,S@EP@$0@E(0@EH)ЉẺiËŋE)ljẺN>뮋 S@AD$A@$A@D$D$$A@US]=wK==D$$ t-$ c'=t)==tWS@t=]]t&D$$pt$и]v'D$$0uD$$~=jD$$tXI$|fD$$a&D$$ A&D$$!UWVS$S@a@S@-Ha@=a@t(v$Ճׅu tC4$Ћ[u$S@4a@[^_]ÍvS@uÍSD$ $tBD$ $S@D$$Ca@S@S@$S@C4a@1[ø'SS@\$ u1[Ð&$S@a@S@t9u N9t(‹Bu$S@4a@1[Ð&HJ$&$S@4a@ыBS@ڍt&SD$$ru S@[ÐS@S@uޡS@tX$ۉuS@S@$S@a@랉'S@tS@[Ív$S@0a@Yt&c@<8PEt1ffx ÍvD$f8MZt1f΍&'VST$ \$R<rBDt1ɐP 9wP9r (9u1[^ÍvUWVS|$0<$i1҃w f=@MZt [^_]Ð@Ft<@@@h\t1 (9t&D$|$$uރډ[^_]f1[^_]Ít&1f=@MZtVS@tJ<@\$ @@@rDt"1ɍP 9rP9r(9u1ɉ[^Ð[^É'1f=@MZtÐ@Ft<@@Ðt&V1f=@MZSL$ t [^Ð&@t<@@@ZDt1f@' tt(9u1[^fƉ[^É'1f=@MZtø@@EЉÉ'1f=@MZtfVS@dtJ<@\$ @@@rDt 1ɍP 9rP9r(9u1[^f@$[^t&WV1f=@MZS\$t [^_Í@t<@@@tyQTtJ 9rJ9r(9u1[^_@u t&HuP tׅp [@^_ÐQP=L$ r -=w) XYÐ%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%|a@%xa@%pa@%la@%`a@%\a@ffffffS@Ív'D$S@ÐU]P'@ p'@0'@@'@N@Dlibgcj-16.dll_Jv_RegisterClasses S@@P@@Unknown error_matherr(): %s in %s(%g, %g) (retval=%g) Argument domain error (DOMAIN)Argument singularity (SIGN)Overflow range error (OVERFLOW)The result is too small to be represented (UNDERFLOW)Total loss of significance (TLOSS)Partial loss of significance (PLOSS)l@@@@@@@@A@$A@Mingw-w64 runtime failure: Address %p has no image-section VirtualQuery failed for %d bytes at address %p VirtualProtect failed with code 0x%x Unknown pseudo relocation protocol version %d. Unknown pseudo relocation bit size %d. GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205<`ea`e\aaaab&bdFdPdXdbdldvddddddaaab&bdFdPdXdbdldvddddddDeleteCriticalSectionEnterCriticalSectionGetCurrentProcessGetCurrentProcessIdGetCurrentThreadIdGetLastErrorGetModuleHandleAEGetProcAddressdGetStartupInfoA{GetSystemTimeAsFileTimeGetTickCountInitializeCriticalSection&LeaveCriticalSectionQueryPerformanceCountergSetUnhandledExceptionFiltertSleepTerminateProcessTlsGetValueUnhandledExceptionFilterVirtualProtectVirtualQuery7__dllonexit:__getmainargs;__initenvD__lconv_inith__set_app_typek__setusermatherry_acmdln_amsg_exit_cexit_fmode0_initterm4_iob_lock2_onexitFcallocPexit`fprintfgfreerfwritemallocmemcpysignalstrlenstrncmp_unlock;abortWvfprintf`````````````````````KERNEL32.dll```````````````````````````msvcrt.dll0@@@@p@@@S@ p@yara-4.5.3/tests/data/tiny-macho000066400000000000000000000100001501365277300165250ustar00rootroot00000000000000 PHi Frand̀jP̀t8SP1jWjPyara-4.5.3/tests/data/tiny-overlay000066400000000000000000001000071501365277300171260ustar00rootroot00000000000000MZ@ !L!This program cannot be run in DOS mode. $PELVV  p0@ܨ `a.textt `P`.data000@0.rdataP@@@0@.bssP`.idata`P@0.CRT4p`@0.tls p@0Í&'1f=@MZS@S@S@$P@thP@S@tJ$$ S@S@S@a@=0@tm1Í&$`f<@@PE@uQf t?f j]1Kv$@1Ãyt,1f,S@D$P@D$P@D$P@$P@P@ P@D$ ,fU1WVUS׃|0)čD$@@@ @@@@̃5S@d1X=@a@9$׃S@uޡS@1ۃS@MP@S@,@@tD$D$$Ѓ b $@ vU,0@t<$@@a@tD$@@$ a@…t $,0@$`@Í&U]ÐUu*ÐffffffS(S@$D$$*S@$YD$S@$HD$D$D$D$D$D$0$$ËD$$*S@D$$$S@d([ÐD$0$a@([Í&'D$ $1Ð0@t fС0@P@0@u Ít&S`'@t!t `'@u$p@[1ÍC`'@uɍv'P@tÐt&P@딐%ha@1ÐUWVS,$0@D$D$=N@tУ(0@,[^_]ÍD$$(a@\$3\$a@a@,a@ƍD$$8a@3\$3\$111N@tЉ5$0@(0@,[^_]ÐDO@t&U( S@ EU$S@$Q@P@,S@EP@$0@E(0@EH)ЉẺiËŋE)ljẺN>뮋 S@AD$A@$A@D$D$$A@US]=wK==D$$ t-$ c'=t)==tWS@t=]]t&D$$pt$и]v'D$$0uD$$~=jD$$tXI$|fD$$a&D$$ A&D$$!UWVS$S@a@S@-Ha@=a@t(v$Ճׅu tC4$Ћ[u$S@4a@[^_]ÍvS@uÍSD$ $tBD$ $S@D$$Ca@S@S@$S@C4a@1[ø'SS@\$ u1[Ð&$S@a@S@t9u N9t(‹Bu$S@4a@1[Ð&HJ$&$S@4a@ыBS@ڍt&SD$$ru S@[ÐS@S@uޡS@tX$ۉuS@S@$S@a@랉'S@tS@[Ív$S@0a@Yt&c@<8PEt1ffx ÍvD$f8MZt1f΍&'VST$ \$R<rBDt1ɐP 9wP9r (9u1[^ÍvUWVS|$0<$i1҃w f=@MZt [^_]Ð@Ft<@@@h\t1 (9t&D$|$$uރډ[^_]f1[^_]Ít&1f=@MZtVS@tJ<@\$ @@@rDt"1ɍP 9rP9r(9u1ɉ[^Ð[^É'1f=@MZtÐ@Ft<@@Ðt&V1f=@MZSL$ t [^Ð&@t<@@@ZDt1f@' tt(9u1[^fƉ[^É'1f=@MZtø@@EЉÉ'1f=@MZtfVS@dtJ<@\$ @@@rDt 1ɍP 9rP9r(9u1[^f@$[^t&WV1f=@MZS\$t [^_Í@t<@@@tyQTtJ 9rJ9r(9u1[^_@u t&HuP tׅp [@^_ÐQP=L$ r -=w) XYÐ%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%|a@%xa@%pa@%la@%`a@%\a@ffffffS@Ív'D$S@ÐU]P'@ p'@0'@@'@N@Dlibgcj-16.dll_Jv_RegisterClasses S@@P@@Unknown error_matherr(): %s in %s(%g, %g) (retval=%g) Argument domain error (DOMAIN)Argument singularity (SIGN)Overflow range error (OVERFLOW)The result is too small to be represented (UNDERFLOW)Total loss of significance (TLOSS)Partial loss of significance (PLOSS)l@@@@@@@@A@$A@Mingw-w64 runtime failure: Address %p has no image-section VirtualQuery failed for %d bytes at address %p VirtualProtect failed with code 0x%x Unknown pseudo relocation protocol version %d. Unknown pseudo relocation bit size %d. GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205<`ea`e\aaaab&bdFdPdXdbdldvddddddaaab&bdFdPdXdbdldvddddddDeleteCriticalSectionEnterCriticalSectionGetCurrentProcessGetCurrentProcessIdGetCurrentThreadIdGetLastErrorGetModuleHandleAEGetProcAddressdGetStartupInfoA{GetSystemTimeAsFileTimeGetTickCountInitializeCriticalSection&LeaveCriticalSectionQueryPerformanceCountergSetUnhandledExceptionFiltertSleepTerminateProcessTlsGetValueUnhandledExceptionFilterVirtualProtectVirtualQuery7__dllonexit:__getmainargs;__initenvD__lconv_inith__set_app_typek__setusermatherry_acmdln_amsg_exit_cexit_fmode0_initterm4_iob_lock2_onexitFcallocPexit`fprintfgfreerfwritemallocmemcpysignalstrlenstrncmp_unlock;abortWvfprintf`````````````````````KERNEL32.dll```````````````````````````msvcrt.dll0@@@@p@@@S@ p@overlayyara-4.5.3/tests/data/tiny-universal000066400000000000000000000605401501365277300174640ustar00rootroot00000000000000!@ @!` $ 8__PAGEZERO__TEXT__text__TEXT__symbol_stub__TEXTf f__stub_helper__TEXTt t__cstring__TEXT__unwind_info__TEXTH__DATA __nl_symbol_ptr__DATA __la_symbol_ptr__DATA 8__LINKEDIT0 @"0  ( D <  H P  /usr/lib/dyldCU];]Ⱥ$ *( 4/usr/lib/libSystem.B.dylib& ) + UEE} E EM $EMȉME]UV4XM UEUMEE䍈U $T$Q=5E$_M䍑EEu$D$t$E4^]% % h % hh%dfactorial( %d ) = %d 44g4 "R!pppQ@dyld_stub_binderQrr@_printfr @_scanf__mh_execute_header,factorial0main5P !'/6@ __mh_execute_header_factorial_main_printf_scanfdyld_stub_binder H__PAGEZERO(__TEXT__text__TEXT__stubs__TEXTF F__stub_helper__TEXTT$T__cstring__TEXTxx__unwind_info__TEXTH__eh_frame__TEXT__DATA__nl_symbol_ptr__DATA__la_symbol_ptr__DATAH__LINKEDIT  `"0   @ @ !H P! /usr/lib/dyldW5-92$ *( 8/usr/lib/libSystem.B.dylib& ) + UHH}} EEMωEMȉMEH]@UHH E}HuH={HuD='}uH=YEuUEH ]Ð%%LAS%hh%dfactorial( %d ) = %d 44F4 zRx dn"R@dyld_stub_binderQrr@_printfr@_scanf__mh_execute_header,factorial0main5P !'/6@ __mh_execute_header_factorial_main_printf_scanfdyld_stub_binderyara-4.5.3/tests/data/tiny.notes000066400000000000000000000014441501365277300166030ustar00rootroot00000000000000tiny.exe was compiled from a simple oneliner, int main() { return 42; } $ i686-w64-mingw32-gcc -s -Wl,--file-alignment=4096 -o tiny.exe tiny.c To demonstrate issue #429, two patched executables have been generated where the PointerToRawData for the .idata section (offset 0x22c) was changed from 0x5000 to 0x51ff (tiny-idata-51ff.exe) and 0x5200 (tiny-idata-5200.exe), respectively. While tiny-idata-51ff.exe can be executed in Windows XP, tiny-idata-5200.exe can not. Compiler version used to produce tiny.exe: $ i686-w64-mingw32-gcc --version i686-w64-mingw32-gcc (GCC) 5.3.1 20160205 Copyright (C) 2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. yara-4.5.3/tests/data/tiny_empty_import_name000066400000000000000000001000001501365277300212500ustar00rootroot00000000000000MZ@ !L!This program cannot be run in DOS mode. $PELVV  p0@ܨ `a.textt `P`.data000@0.rdataP@@@0@.bssP`.idata`P@0.CRT4p`@0.tls p@0Í&'1f=@MZS@S@S@$P@thP@S@tJ$$ S@S@S@a@=0@tm1Í&$`f<@@PE@uQf t?f j]1Kv$@1Ãyt,1f,S@D$P@D$P@D$P@$P@P@ P@D$ ,fU1WVUS׃|0)čD$@@@ @@@@̃5S@d1X=@a@9$׃S@uޡS@1ۃS@MP@S@,@@tD$D$$Ѓ b $@ vU,0@t<$@@a@tD$@@$ a@…t $,0@$`@Í&U]ÐUu*ÐffffffS(S@$D$$*S@$YD$S@$HD$D$D$D$D$D$0$$ËD$$*S@D$$$S@d([ÐD$0$a@([Í&'D$ $1Ð0@t fС0@P@0@u Ít&S`'@t!t `'@u$p@[1ÍC`'@uɍv'P@tÐt&P@딐%ha@1ÐUWVS,$0@D$D$=N@tУ(0@,[^_]ÍD$$(a@\$3\$a@a@,a@ƍD$$8a@3\$3\$111N@tЉ5$0@(0@,[^_]ÐDO@t&U( S@ EU$S@$Q@P@,S@EP@$0@E(0@EH)ЉẺiËŋE)ljẺN>뮋 S@AD$A@$A@D$D$$A@US]=wK==D$$ t-$ c'=t)==tWS@t=]]t&D$$pt$и]v'D$$0uD$$~=jD$$tXI$|fD$$a&D$$ A&D$$!UWVS$S@a@S@-Ha@=a@t(v$Ճׅu tC4$Ћ[u$S@4a@[^_]ÍvS@uÍSD$ $tBD$ $S@D$$Ca@S@S@$S@C4a@1[ø'SS@\$ u1[Ð&$S@a@S@t9u N9t(‹Bu$S@4a@1[Ð&HJ$&$S@4a@ыBS@ڍt&SD$$ru S@[ÐS@S@uޡS@tX$ۉuS@S@$S@a@랉'S@tS@[Ív$S@0a@Yt&c@<8PEt1ffx ÍvD$f8MZt1f΍&'VST$ \$R<rBDt1ɐP 9wP9r (9u1[^ÍvUWVS|$0<$i1҃w f=@MZt [^_]Ð@Ft<@@@h\t1 (9t&D$|$$uރډ[^_]f1[^_]Ít&1f=@MZtVS@tJ<@\$ @@@rDt"1ɍP 9rP9r(9u1ɉ[^Ð[^É'1f=@MZtÐ@Ft<@@Ðt&V1f=@MZSL$ t [^Ð&@t<@@@ZDt1f@' tt(9u1[^fƉ[^É'1f=@MZtø@@EЉÉ'1f=@MZtfVS@dtJ<@\$ @@@rDt 1ɍP 9rP9r(9u1[^f@$[^t&WV1f=@MZS\$t [^_Í@t<@@@tyQTtJ 9rJ9r(9u1[^_@u t&HuP tׅp [@^_ÐQP=L$ r -=w) XYÐ%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%a@%|a@%xa@%pa@%la@%`a@%\a@ffffffS@Ív'D$S@ÐU]P'@ p'@0'@@'@N@Dlibgcj-16.dll_Jv_RegisterClasses S@@P@@Unknown error_matherr(): %s in %s(%g, %g) (retval=%g) Argument domain error (DOMAIN)Argument singularity (SIGN)Overflow range error (OVERFLOW)The result is too small to be represented (UNDERFLOW)Total loss of significance (TLOSS)Partial loss of significance (PLOSS)l@@@@@@@@A@$A@Mingw-w64 runtime failure: Address %p has no image-section VirtualQuery failed for %d bytes at address %p VirtualProtect failed with code 0x%x Unknown pseudo relocation protocol version %d. Unknown pseudo relocation bit size %d. GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205GCC: (GNU) 5.3.1 20160205<`ea`e\aaaab&bdFdPdXdbdldvddddddaaab&bdFdPdXdbdldvddddddEnterriticalSection._?@$()<>tProcessGetCurrentProcessIdGetCurrentThreadIdGetLastErrorGetModuleHandleAEGetProcAddressdGetStartupInfoA{GetSystemTimeAsFileTimeGetTickCountInitializeCriticalSection&LeaveCriticalSectionQueryPerformanceCountergSetUnhandledExceptionFiltertSleepTerminateProcessTlsGetValueUnhandledExceptionFilterVirtualProtectVirtualQuery7__dllonexit:__getmainargs;__initenvD__lconv_inith__set_app_typek__setusermatherry_acmdln_amsg_exit_cexit_fmode0_initterm4_iob_lock2_onexitFcallocPexit`fprintfgfreerfwritemallocmemcpysignalstrlenstrncmp_unlock;abortWvfprintf`````````````````````KERNEL32.dll```````````````````````````msvcrt.dll0@@@@p@@@S@ p@yara-4.5.3/tests/data/weird_rich000066400000000000000000000015101501365277300166020ustar00rootroot00000000000000MZ@P !L!This program cannot be run in DOS mode. $UsҊ@RichPELM  "("!PHyara-4.5.3/tests/data/x.txt000066400000000000000000036412431501365277300155700ustar00rootroot00000000000000XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXyara-4.5.3/tests/data/xor.out000066400000000000000000000143571501365277300161160ustar00rootroot000000000000000x0 This program cannot 0x1 Uihr!qsnfs`l!b`oonu 0x2 Vjkq"rpmepco"acllmv 0x3 Wkjp#sqldqbn#`bmmlw 0x4 Plmw$tvkcvei$gejjkp 0x5 Qmlv%uwjbwdh%fdkkjq 0x6 Rnou&vtiatgk&eghhir 0x7 Sont'wuh`ufj'dfiihs 0x8 \`a{(xzgozie(kiffg| 0x9 ]a`z)y{fn{hd)jhggf} 0xa ^bcy*zxemxkg*ikdde~ 0xb _cbx+{ydlyjf+hjeed 0xc Xde,|~ck~ma,ombbcx 0xd Yed~-}bjl`-nlccby 0xe Zfg}.~|ai|oc.mo``az 0xf [gf|/}`h}nb/lnaa`{ 0x10 Dxyc0`bwbq}0sq~~d 0x11 Eyxb1ac~vcp|1rp~e 0x12 Fz{a2b`}u`s2qs||}f 0x13 G{z`3ca|tar~3pr}}|g 0x14 @|}g4df{sfuy4wuzz{` 0x15 A}|f5egzrgtx5vt{{za 0x16 B~e6fdyqdw{6uwxxyb 0x17 C~d7gexpevz7tvyyxc 0x18 Lpqk8hjwjyu8{yvvwl 0x19 Mqpj9ikv~kxt9zxwwvm 0x1a Nrsi:jhu}h{w:y{ttun 0x1b Osrh;kit|izv;xzuuto 0x1c Htuonlqyls>}ppqj 0x1f Kwvl?ompxm~r?|~qqpk 0x20 tHISPROGRAMCANNOT 0x21 uIHRQSNFS@LB@OONU 0x22 vJKQRPMEPCOACLLMV 0x23 wKJPSQLDQBN@BMMLW 0x24 pLMWTVKCVEIGEJJKP 0x25 qMLVUWJBWDHFDKKJQ 0x26 rNOUVTIATGKEGHHIR 0x27 sONTWUH@UFJDFIIHS 0x28 |@A[XZGOZIEKIFFG\ 0x29 }A@Z Y[FN[HD JHGGF] 0x2a ~BCY ZXEMXKG IKDDE^ 0x2b CBX [YDLYJF HJEED_ 0x2c xDE_ \^CK^MA OMBBCX 0x2d yED^ ]_BJ_L@ NLCCBY 0x2e zFG]^\AI\OCMO@@AZ 0x2f {GF\_]@H]NBLNAA@[ 0x30 dXYC@B_WBQ]SQ^^_D 0x31 eYXBAC^VCP\RP__^E 0x32 fZ[AB@]U@S_QS\\]F 0x33 g[Z@CA\TAR^PR]]\G 0x34 `\]GDF[SFUYWUZZ[@ 0x35 a]\FEGZRGTXVT[[ZA 0x36 b^_EFDYQDW[UWXXYB 0x37 c_^DGEXPEVZTVYYXC 0x38 lPQKHJW_JYU[YVVWL 0x39 mQPJIKV^KXTZXWWVM 0x3a nRSIJHU]H[WY[TTUN 0x3b oSRHKIT\IZVXZUUTO 0x3c hTUOLNS[N]Q_]RRSH 0x3d iUTNMORZO\P^\SSRI 0x3e jVWMNLQYL_S]_PPQJ 0x3f kWVLOMPXM^R\^QQPK 0x40 ()3`02/'2!-`#!../4 0x41 )(2a13.&3 ,a" //.5 0x42 *+1b20-%0#/b!#,,-6 0x43 +*0c31,$1".c "--,7 0x44 ,-7d46+#6%)d'%**+0 0x45 -,6e57*"7$(e&$++*1 0x46 ./5f64)!4'+f%'(()2 0x47 /.4g75( 5&*g$&))(3 0x48  !;h8:'/:)%h+)&&'< 0x49 ! :i9;&.;($i*(''&= 0x4a "#9j:8%-8+'j)+$$%> 0x4b #"8k;9$,9*&k(*%%$? 0x4c $%?l<>#+>-!l/-""#8 0x4d %$>m=?"*?, m.,##"9 0x4e &'=n>>?$ 0x51 98"q!#>6#0% 0x52 :;!r" =5 3?r13<<=& 0x53 ;: s#!<4!2>s02==<' 0x54 <='t$&;3&59t75::; 0x55 =<&u%':2'48u64;;:! 0x56 >?%v&$91$7;v57889" 0x57 ?>$w'%80%6:w46998# 0x58 01+x(*7?*95x;9667, 0x59 10*y)+6>+84y:8776- 0x5a 23)z*(5=(;7z9;445. 0x5b 32({+)4<):6{8:554/ 0x5c 45/|,.3;.=1|?=223( 0x5d 54.}-/2:/<0}><332) 0x5e 67-~.,19,?3~=?001* 0x5f 76,/-08->2<>110+ 0x60 4 @ @ 0x61 5 A A 0x62 6 B B  0x63 7 C C  0x64 0 D  D  0x65 1 E E  0x66 2F  F  0x67 3G G  0x68 <H H  0x69 =II  0x6a >J  J  0x6b ?K  K  0x6c 8L  L  0x6d 9M  M  0x6e :N N  0x6f ;OO  0x70 $PP 0x71 %QQ 0x72 &RR 0x73 'SS 0x74 TT 0x75 !UU 0x76 "VV 0x77 #WW 0x78 , X  X 0x79 - Y  Y 0x7a . Z Z 0x7b /[  [ 0x7c (\ \ 0x7d )] ] 0x7e * ^  ^ 0x7f + _  _ 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9a 0x9b 0x9c 0x9d 0x9e 0x9f 0xa0 Ӏ̀ 0xa1 ҁ́ 0xa2 тς 0xa3 Ѓ΃ 0xa4 ׄɄ 0xa5 օȅ 0xa6 Նˆ 0xa7 ԇʇ 0xa8 ۈň 0xa9 ډĉ 0xaa يNJ 0xab ؋Ƌ 0xac ߌ 0xad ލ 0xae ݎÎ 0xaf ܏ 0xb0 Ðݐ 0xb1 ‘ܑ 0xb2 ߒ 0xb3 ޓ 0xb4 ǔٔ 0xb5 ƕؕ 0xb6 Ŗۖ 0xb7 ėڗ 0xb8 ˘՘ 0xb9 ʙԙ 0xba ɚך 0xbb ț֛ 0xbc Ϝќ 0xbd ΝН 0xbe ͞Ӟ 0xbf ̟ҟ 0xc0 ల࣡ 0xc1 ᱳᢠ 0xc2 Ⲱ⡣ 0xc3 㳱㠢 0xc4 䴶䧥 0xc5 嵷妤 0xc6 涴楧 0xc7 緵礦 0xc8 踺諩 0xc9 鹻骨 0xca 꺸ꩫ 0xcb 뻹먪 0xcc 켾쯭 0xcd 0xce  0xcf �אַ 0xd0 𠢿𳱾 0xd1 񡣾񲰿 0xd2 򢠽򱳼 0xd3 󣡼󰲽 0xd4 0xd5 0xd6 0xd7 0xd8 0xd9 0xda 0xdb 0xdc 0xdd 0xde 0xdf 0xe0 0xe1 0xe2 ’ 0xe3 ÓÀ 0xe4 Ĕć 0xe5 ŕņ 0xe6 Ɩƅ 0xe7 ǗDŽ 0xe8 Șȋ 0xe9 əɊ 0xea ʚʉ 0xeb ˛ˈ 0xec ̜̏ 0xed ͎͝ 0xee Ξ΍ 0xef ϟό 0xf0 ЀГ 0xf1 сђ 0xf2 ҂ґ 0xf3 ӃӐ 0xf4 Ԅԗ 0xf5 ՅՖ 0xf6 ֆ֕ 0xf7 ׇה 0xf8 ؈؛ 0xf9 ىٚ 0xfa ڊڙ 0xfb ۋۘ 0xfc ܌ܟ 0xfd ݍݞ 0xfe ގޝ 0xff ߏߜyara-4.5.3/tests/data/xorwide.out000066400000000000000000000257571501365277300167750ustar00rootroot000000000000000x0 This program cannot 0x1 Uihr!qsnfs`l!b`oonu 0x2 Vjkq"rpmepco"acllmv 0x3 Wkjp#sqldqbn#`bmmlw 0x4 Plmw$tvkcvei$gejjkp 0x5 Qmlv%uwjbwdh%fdkkjq 0x6 Rnou&vtiatgk&eghhir 0x7 Sont'wuh`ufj'dfiihs 0x8 \`a{(xzgozie(kiffg| 0x9 ] a ` z ) y { f n { h d ) j h g g f } 0xa ^ b c y * z x e m x k g * i k d d e ~ 0xb _ c b x + { y d l y j f + h j e e d  0xc X d e  , | ~ c k ~ m a , o m b b c x 0xd Y e d ~ - }  b j  l ` - n l c c b y 0xe Zfg}.~|ai|oc.mo``az 0xf [gf|/}`h}nb/lnaa`{ 0x10 Dxyc0`bwbq}0sq~~d 0x11 Eyxb1ac~vcp|1rp~e 0x12 Fz{a2b`}u`s2qs||}f 0x13 G{z`3ca|tar~3pr}}|g 0x14 @|}g4df{sfuy4wuzz{` 0x15 A}|f5egzrgtx5vt{{za 0x16 B~e6fdyqdw{6uwxxyb 0x17 C~d7gexpevz7tvyyxc 0x18 Lpqk8hjwjyu8{yvvwl 0x19 Mqpj9ikv~kxt9zxwwvm 0x1a Nrsi:jhu}h{w:y{ttun 0x1b Osrh;kit|izv;xzuuto 0x1c Htuo<lns{n}q<}rrsh 0x1d Iutn=morzo|p=~|ssri 0x1e Jvwm>nlqyls>}ppqj 0x1f Kwvl?ompxm~r?|~qqpk 0x20 t H I S P R O G R A M C A N N O T 0x21 u!I!H!R!!Q!S!N!F!S!@!L!!B!@!O!O!N!U! 0x22 v"J"K"Q""R"P"M"E"P"C"O""A"C"L"L"M"V" 0x23 w#K#J#P##S#Q#L#D#Q#B#N##@#B#M#M#L#W# 0x24 p$L$M$W$$T$V$K$C$V$E$I$$G$E$J$J$K$P$ 0x25 q%M%L%V%%U%W%J%B%W%D%H%%F%D%K%K%J%Q% 0x26 r&N&O&U&&V&T&I&A&T&G&K&&E&G&H&H&I&R& 0x27 s'O'N'T''W'U'H'@'U'F'J''D'F'I'I'H'S' 0x28 |(@(A([((X(Z(G(O(Z(I(E((K(I(F(F(G(\( 0x29 })A)@)Z) )Y)[)F)N)[)H)D) )J)H)G)G)F)]) 0x2a ~*B*C*Y* *Z*X*E*M*X*K*G* *I*K*D*D*E*^* 0x2b +C+B+X+ +[+Y+D+L+Y+J+F+ +H+J+E+E+D+_+ 0x2c x,D,E,_, ,\,^,C,K,^,M,A, ,O,M,B,B,C,X, 0x2d y-E-D-^- -]-_-B-J-_-L-@- -N-L-C-C-B-Y- 0x2e z.F.G.]..^.\.A.I.\.O.C..M.O.@.@.A.Z. 0x2f {/G/F/\//_/]/@/H/]/N/B//L/N/A/A/@/[/ 0x30 d0X0Y0C00@0B0_0W0B0Q0]00S0Q0^0^0_0D0 0x31 e1Y1X1B11A1C1^1V1C1P1\11R1P1_1_1^1E1 0x32 f2Z2[2A22B2@2]2U2@2S2_22Q2S2\2\2]2F2 0x33 g3[3Z3@33C3A3\3T3A3R3^33P3R3]3]3\3G3 0x34 `4\4]4G44D4F4[4S4F4U4Y44W4U4Z4Z4[4@4 0x35 a5]5\5F55E5G5Z5R5G5T5X55V5T5[5[5Z5A5 0x36 b6^6_6E66F6D6Y6Q6D6W6[66U6W6X6X6Y6B6 0x37 c7_7^7D77G7E7X7P7E7V7Z77T7V7Y7Y7X7C7 0x38 l8P8Q8K88H8J8W8_8J8Y8U88[8Y8V8V8W8L8 0x39 m9Q9P9J99I9K9V9^9K9X9T99Z9X9W9W9V9M9 0x3a n:R:S:I::J:H:U:]:H:[:W::Y:[:T:T:U:N: 0x3b o;S;R;H;;K;I;T;\;I;Z;V;;X;Z;U;U;T;O; 0x3c hV>W>M>>N>L>Q>Y>L>_>S>>]>_>P>P>Q>J> 0x3f k?W?V?L??O?M?P?X?M?^?R??\?^?Q?Q?P?K? 0x40 @(@)@3@`@0@2@/@'@2@!@-@`@#@!@.@.@/@4@ 0x41 A)A(A2AaA1A3A.A&A3A A,AaA"A A/A/A.A5A 0x42 B*B+B1BbB2B0B-B%B0B#B/BbB!B#B,B,B-B6B 0x43 C+C*C0CcC3C1C,C$C1C"C.CcC C"C-C-C,C7C 0x44 D,D-D7DdD4D6D+D#D6D%D)DdD'D%D*D*D+D0D 0x45 E-E,E6EeE5E7E*E"E7E$E(EeE&E$E+E+E*E1E 0x46 F.F/F5FfF6F4F)F!F4F'F+FfF%F'F(F(F)F2F 0x47 G/G.G4GgG7G5G(G G5G&G*GgG$G&G)G)G(G3G 0x48 H H!H;HhH8H:H'H/H:H)H%HhH+H)H&H&H'HJ 0x4b K#K"K8KkK;K9K$K,K9K*K&KkK(K*K%K%K$K?K 0x4c L$L%L?LlLL#L+L>L-L!LlL/L-L"L"L#L8L 0x4d M%M$M>MmM=M?M"M*M?M,M MmM.M,M#M#M"M9M 0x4e N&N'N=NnN>NP>P?P$P 0x51 Q9Q8Q"QqQ!Q#Q>Q6Q#Q0QQ%Q 0x52 R:R;R!RrR"R R=R5R R3R?RrR1R3RSsS0S2S=S=SV?V%VvV&V$V9V1V$V7V;VvV5V7V8V8V9V"V 0x57 W?W>W$WwW'W%W8W0W%W6W:WwW4W6W9W9W8W#W 0x58 X0X1X+XxX(X*X7X?X*X9X5XxX;X9X6X6X7X,X 0x59 Y1Y0Y*YyY)Y+Y6Y>Y+Y8Y4YyY:Y8Y7Y7Y6Y-Y 0x5a Z2Z3Z)ZzZ*Z(Z5Z=Z(Z;Z7ZzZ9Z;Z4Z4Z5Z.Z 0x5b [3[2[([{[+[)[4[<[)[:[6[{[8[:[5[5[4[/[ 0x5c \4\5\/\|\,\.\3\;\.\=\1\|\?\=\2\2\3\(\ 0x5d ]5]4].]}]-]/]2]:]/]<]0]}]>]<]3]3]2])] 0x5e ^6^7^-^~^.^,^1^9^,^?^3^~^=^?^0^0^1^*^ 0x5f _7_6_,__/_-_0_8_-_>_2__<_>_1_1_0_+_ 0x60 4`` ``@``````` `@``````` 0x61 5a aaaAaaaaaaa aAaaaaaaa 0x62 6b b bbBbbb bbbbbBbbb b b bb 0x63 7c c ccCccc cccccCccc c c cc 0x64 0d d ddDddd dddd dDddd d d dd 0x65 1e e eeEeee eeeeeEeee e e ee 0x66 2ffffFfff ffff fFfffff ff 0x67 3ggggGggggggg gGggg g ggg 0x68 jjjjJjjjj jj jjJj j jjjjj 0x6b ?kkkkKkkkk kk kkKkk kkkkk 0x6c 8llllLllll ll llLll lllll 0x6d 9mmmmMmmmm mm mmMmm mmmmm 0x6e :nnnnNnnnn nnnnNn nnnnnn 0x6f ;ooooOooooooooOo oooooo 0x70 $ppppPppppppppPppppppp 0x71 %qqqqQqqqqqqqqQqqqqqqq 0x72 &rrrrRrrrrrrrrRrrrrrrr 0x73 'ssssSssssssssSsssssss 0x74 ttttTttttttttTttttttt 0x75 !uuuuUuuuuuuuuUuuuuuuu 0x76 "vvvvVvvvvvvvvVvvvvvvv 0x77 #wwwwWwwwwwwwwWwwwwwww 0x78 ,xxx xXxx xxx xxxXxxxxxx x 0x79 -yyy yYy y yyy yyyYyyyyyy y 0x7a .zzz zZz zzzzzzzZzzzzzzz 0x7b /{{{{[{ { {{{ {{{[{{{{{{{ 0x7c (||||\| |||||||\||||||| 0x7d )}}}}]} }}}}}}}]}}}}}} } 0x7e *~~~ ~^~~ ~~~ ~~~^~~~~~~ ~ 0x7f + _  _  0x80 Ԁ󀠀퀠 0x81 Ձ򁡁쁡 0x82 ւ񂢂 0x83 ׃ 0x84 Є鄤 0x85 х腥 0x86 ҆놦 0x87 Ӈ􇧇ꇧ 0x88 ܈刨 0x89 ݉䉩 0x8a ފ犪 0x8b ߋ拫 0x8c ،ጬ 0x8d ٍ 0x8e ڎ㎮ 0x8f ۏ⏯ 0x90 Đ㐰 0x91 ő⑱ 0x92 ƒᒲ 0x93 Ǔ 0x94 甴 0x95 敵 0x96 –営 0x97 ×䗷 0x98 ̘똸 0x99 ͙ꙹ 0x9a Κ隺 0x9b ϛ蛻 0x9c Ȝ񜼜 0x9d ɝ𝽝 0x9e ʞힾ󞾞 0x9f ˟쟿򟿟 0xa0 ȠɠӠРҠϠǠҠ͠àΠΠϠԠ 0xa1 ɡȡҡѡӡΡơӡ̡¡ϡϡΡա 0xa2 ʢˢѢҢТ͢ŢТâϢâ̢̢֢͢ 0xa3 ˣʣУӣѣ̣ģѣ£Σ£̣ͣͣף 0xa4 ̤ͤפԤ֤ˤä֤ŤɤǤŤʤʤˤФ 0xa5 ̥֥ͥեץʥ¥ץĥȥƥĥ˥˥ʥѥ 0xa6 ΦϦզ֦ԦɦԦǦ˦ŦǦȦȦɦҦ 0xa7 ϧΧԧקէȧէƧʧħƧɧɧȧӧ 0xa8 ۨبڨǨϨڨɨŨ˨ɨƨƨǨܨ 0xa9 ک٩۩ƩΩ۩ȩĩʩȩǩǩƩݩ 0xaa ªê٪ڪتŪͪت˪Ǫɪ˪ĪĪŪު 0xab ë«ث۫٫ī̫٫ʫƫȫʫūūī߫ 0xac ĬŬ߬ܬެìˬެͬϬͬ¬¬ìج 0xad ŭĭޭݭ߭­ʭ̭߭έ̭íí­٭ 0xae ƮǮݮޮܮɮܮϮîͮϮڮ 0xaf ǯƯܯ߯ݯȯݯί¯̯ίۯ 0xb0 ذٰð°߰װ°ѰݰӰѰްް߰İ 0xb1 ٱر±ñޱֱñбܱұб߱߱ޱű 0xb2 ڲ۲²ݲղӲ߲ѲӲܲܲݲƲ 0xb3 ۳ڳóܳԳҳ޳гҳݳݳܳdz 0xb4 ܴݴǴĴƴ۴Ӵƴմٴ״մڴڴ۴ 0xb5 ݵܵƵŵǵڵҵǵԵصֵԵ۵۵ڵ 0xb6 ޶߶ŶƶĶٶѶĶ׶۶ն׶ضضٶ¶ 0xb7 ߷޷ķǷŷطзŷַڷԷַٷٷط÷ 0xb8 иѸ˸ȸʸ׸߸ʸٸո۸ٸָָ׸̸ 0xb9 ѹйʹɹ˹ֹ޹˹عԹڹع׹׹ֹ͹ 0xba ҺӺɺʺȺպݺȺۺ׺ٺۺԺԺպκ 0xbb ӻһȻ˻ɻԻܻɻڻֻػڻջջԻϻ 0xbc Լռϼ̼μӼۼμݼѼ߼ݼҼҼӼȼ 0xbd սԽνͽϽҽڽϽܽн޽ܽӽӽҽɽ 0xbe ־׾;ξ̾Ѿپ̾߾Ӿݾ߾ооѾʾ 0xbf ׿ֿ̿ϿͿпؿͿ޿ҿܿ޿ѿѿп˿ 0xc0 0xc1 0xc2 ª«±²°­¥°£¯¡£¬¬­¶ 0xc3 ëêðóñìäñâîàâííì÷ 0xc4 ĬĭķĴĶīģĶĥĩħĥĪĪīİ 0xc5 ŭŬŶŵŷŪŢŷŤŨŦŤūūŪű 0xc6 ƮƯƵƶƴƩơƴƧƫƥƧƨƨƩƲ 0xc7 ǯǮǴǷǵǨǠǵǦǪǤǦǩǩǨdz 0xc8 ȠȡȻȸȺȧȯȺȩȥȫȩȦȦȧȼ 0xc9 ɡɠɺɹɻɦɮɻɨɤɪɨɧɧɦɽ 0xca ʢʣʹʺʸʥʭʸʫʧʩʫʤʤʥʾ 0xcb ˣˢ˸˻˹ˤˬ˹˪˦˨˪˥˥ˤ˿ 0xcc ̸̡̢̢̤̥̼̣̫̭̯̭̣̿̾̾ 0xcd ͥͤ;ͽͿͪ͢Ϳͬͮͬͣͣ͢͠͹ 0xce ΦΧνξμΡΩμίΣέίΠΠΡκ 0xcf ϧϦϼϿϽϠϨϽϮϢϬϮϡϡϠϻ 0xd0 ийУРТпзТбнгбоопФ 0xd1 ѹѸѢѡѣѾѶѣѰѼѲѰѿѿѾѥ 0xd2 ҺһҡҢҠҽҵҠҳҿұҳҼҼҽҦ 0xd3 ӻӺӠӣӡӼӴӡӲӾӰӲӽӽӼӧ 0xd4 ԼԽԧԤԦԻԳԦԵԹԷԵԺԺԻԠ 0xd5 սռզեէպղէմոնմջջպա 0xd6 ־ֱֵַַָָֹֹֻֿ֥֦֤֤֢ 0xd7 ׿׾פקץ׸װץ׶׺״׶׹׹׸ף 0xd8 ذرثبتطؿتعصػعضضطج 0xd9 ٱٰ٪٩٫ٶپ٫ٸٴٺٸٷٷٶ٭ 0xda ڲڳکڪڨڵڽڨڻڷڹڻڴڴڵڮ 0xdb ۳۲ۨ۫۩۴ۼ۩ۺ۶۸ۺ۵۵۴ۯ 0xdc ܴܵܯܬܮܻܳܮܱܽܿܽܲܲܳܨ 0xdd ݵݴݮݭݯݲݺݯݼݰݾݼݳݳݲݩ 0xde ޶޷ޭޮެޱ޹ެ޿޳޽޿ްްޱު 0xdf ߷߶߬߯߭߰߸߭߾߲߼߾߱߱߰߫ 0xe0 0xe1 0xe2 0xe3 0xe4 0xe5 0xe6 0xe7 0xe8 0xe9 0xea 0xeb 0xec 0xed 0xee 0xef 0xf0 0xf1 0xf2 0xf3 0xf4 0xf5 0xf6 0xf7 0xf8 0xf9 0xfa 0xfb 0xfc 0xfd 0xfe 0xff yara-4.5.3/tests/data/xorwideandascii.out000066400000000000000000000423401501365277300204540ustar00rootroot000000000000000x0 This program cannot 0x1 Uihr!qsnfs`l!b`oonu 0x2 Vjkq"rpmepco"acllmv 0x3 Wkjp#sqldqbn#`bmmlw 0x4 Plmw$tvkcvei$gejjkp 0x5 Qmlv%uwjbwdh%fdkkjq 0x6 Rnou&vtiatgk&eghhir 0x7 Sont'wuh`ufj'dfiihs 0x8 \`a{(xzgozie(kiffg| 0x9 ]a`z)y{fn{hd)jhggf} 0xa ^bcy*zxemxkg*ikdde~ 0xb _cbx+{ydlyjf+hjeed 0xc Xde,|~ck~ma,ombbcx 0xd Yed~-}bjl`-nlccby 0xe Zfg}.~|ai|oc.mo``az 0xf [gf|/}`h}nb/lnaa`{ 0x10 Dxyc0`bwbq}0sq~~d 0x11 Eyxb1ac~vcp|1rp~e 0x12 Fz{a2b`}u`s2qs||}f 0x13 G{z`3ca|tar~3pr}}|g 0x14 @|}g4df{sfuy4wuzz{` 0x15 A}|f5egzrgtx5vt{{za 0x16 B~e6fdyqdw{6uwxxyb 0x17 C~d7gexpevz7tvyyxc 0x18 Lpqk8hjwjyu8{yvvwl 0x19 Mqpj9ikv~kxt9zxwwvm 0x1a Nrsi:jhu}h{w:y{ttun 0x1b Osrh;kit|izv;xzuuto 0x1c Htuonlqyls>}ppqj 0x1f Kwvl?ompxm~r?|~qqpk 0x20 tHISPROGRAMCANNOT 0x21 uIHRQSNFS@LB@OONU 0x22 vJKQRPMEPCOACLLMV 0x23 wKJPSQLDQBN@BMMLW 0x24 pLMWTVKCVEIGEJJKP 0x25 qMLVUWJBWDHFDKKJQ 0x26 rNOUVTIATGKEGHHIR 0x27 sONTWUH@UFJDFIIHS 0x28 |@A[XZGOZIEKIFFG\ 0x29 }A@Z Y[FN[HD JHGGF] 0x2a ~BCY ZXEMXKG IKDDE^ 0x2b CBX [YDLYJF HJEED_ 0x2c xDE_ \^CK^MA OMBBCX 0x2d yED^ ]_BJ_L@ NLCCBY 0x2e zFG]^\AI\OCMO@@AZ 0x2f {GF\_]@H]NBLNAA@[ 0x30 dXYC@B_WBQ]SQ^^_D 0x31 eYXBAC^VCP\RP__^E 0x32 fZ[AB@]U@S_QS\\]F 0x33 g[Z@CA\TAR^PR]]\G 0x34 `\]GDF[SFUYWUZZ[@ 0x35 a]\FEGZRGTXVT[[ZA 0x36 b^_EFDYQDW[UWXXYB 0x37 c_^DGEXPEVZTVYYXC 0x38 lPQKHJW_JYU[YVVWL 0x39 mQPJIKV^KXTZXWWVM 0x3a nRSIJHU]H[WY[TTUN 0x3b oSRHKIT\IZVXZUUTO 0x3c hTUOLNS[N]Q_]RRSH 0x3d iUTNMORZO\P^\SSRI 0x3e jVWMNLQYL_S]_PPQJ 0x3f kWVLOMPXM^R\^QQPK 0x40 ()3`02/'2!-`#!../4 0x41 )(2a13.&3 ,a" //.5 0x42 *+1b20-%0#/b!#,,-6 0x43 +*0c31,$1".c "--,7 0x44 ,-7d46+#6%)d'%**+0 0x45 -,6e57*"7$(e&$++*1 0x46 ./5f64)!4'+f%'(()2 0x47 /.4g75( 5&*g$&))(3 0x48  !;h8:'/:)%h+)&&'< 0x49 ! :i9;&.;($i*(''&= 0x4a "#9j:8%-8+'j)+$$%> 0x4b #"8k;9$,9*&k(*%%$? 0x4c $%?l<>#+>-!l/-""#8 0x4d %$>m=?"*?, m.,##"9 0x4e &'=n>>?$ 0x51 98"q!#>6#0% 0x52 :;!r" =5 3?r13<<=& 0x53 ;: s#!<4!2>s02==<' 0x54 <='t$&;3&59t75::; 0x55 =<&u%':2'48u64;;:! 0x56 >?%v&$91$7;v57889" 0x57 ?>$w'%80%6:w46998# 0x58 01+x(*7?*95x;9667, 0x59 10*y)+6>+84y:8776- 0x5a 23)z*(5=(;7z9;445. 0x5b 32({+)4<):6{8:554/ 0x5c 45/|,.3;.=1|?=223( 0x5d 54.}-/2:/<0}><332) 0x5e 67-~.,19,?3~=?001* 0x5f 76,/-08->2<>110+ 0x60 4 @ @ 0x61 5 A A 0x62 6 B B  0x63 7 C C  0x64 0 D  D  0x65 1 E E  0x66 2F  F  0x67 3G G  0x68 <H H  0x69 =II  0x6a >J  J  0x6b ?K  K  0x6c 8L  L  0x6d 9M  M  0x6e :N N  0x6f ;OO  0x70 $PP 0x71 %QQ 0x72 &RR 0x73 'SS 0x74 TT 0x75 !UU 0x76 "VV 0x77 #WW 0x78 , X  X 0x79 - Y  Y 0x7a . Z Z 0x7b /[  [ 0x7c (\ \ 0x7d )] ] 0x7e * ^  ^ 0x7f + _  _ 0x80 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f 0x90 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 0x99 0x9a 0x9b 0x9c 0x9d 0x9e 0x9f 0xa0 Ӏ̀ 0xa1 ҁ́ 0xa2 тς 0xa3 Ѓ΃ 0xa4 ׄɄ 0xa5 օȅ 0xa6 Նˆ 0xa7 ԇʇ 0xa8 ۈň 0xa9 ډĉ 0xaa يNJ 0xab ؋Ƌ 0xac ߌ 0xad ލ 0xae ݎÎ 0xaf ܏ 0xb0 Ðݐ 0xb1 ‘ܑ 0xb2 ߒ 0xb3 ޓ 0xb4 ǔٔ 0xb5 ƕؕ 0xb6 Ŗۖ 0xb7 ėڗ 0xb8 ˘՘ 0xb9 ʙԙ 0xba ɚך 0xbb ț֛ 0xbc Ϝќ 0xbd ΝН 0xbe ͞Ӟ 0xbf ̟ҟ 0xc0 ల࣡ 0xc1 ᱳᢠ 0xc2 Ⲱ⡣ 0xc3 㳱㠢 0xc4 䴶䧥 0xc5 嵷妤 0xc6 涴楧 0xc7 緵礦 0xc8 踺諩 0xc9 鹻骨 0xca 꺸ꩫ 0xcb 뻹먪 0xcc 켾쯭 0xcd 0xce  0xcf �אַ 0xd0 𠢿𳱾 0xd1 񡣾񲰿 0xd2 򢠽򱳼 0xd3 󣡼󰲽 0xd4 0xd5 0xd6 0xd7 0xd8 0xd9 0xda 0xdb 0xdc 0xdd 0xde 0xdf 0xe0 0xe1 0xe2 ’ 0xe3 ÓÀ 0xe4 Ĕć 0xe5 ŕņ 0xe6 Ɩƅ 0xe7 ǗDŽ 0xe8 Șȋ 0xe9 əɊ 0xea ʚʉ 0xeb ˛ˈ 0xec ̜̏ 0xed ͎͝ 0xee Ξ΍ 0xef ϟό 0xf0 ЀГ 0xf1 сђ 0xf2 ҂ґ 0xf3 ӃӐ 0xf4 Ԅԗ 0xf5 ՅՖ 0xf6 ֆ֕ 0xf7 ׇה 0xf8 ؈؛ 0xf9 ىٚ 0xfa ڊڙ 0xfb ۋۘ 0xfc ܌ܟ 0xfd ݍݞ 0xfe ގޝ 0xff ߏߜ 0x0 This program cannot 0x1 Uihr!qsnfs`l!b`oonu 0x2 Vjkq"rpmepco"acllmv 0x3 Wkjp#sqldqbn#`bmmlw 0x4 Plmw$tvkcvei$gejjkp 0x5 Qmlv%uwjbwdh%fdkkjq 0x6 Rnou&vtiatgk&eghhir 0x7 Sont'wuh`ufj'dfiihs 0x8 \`a{(xzgozie(kiffg| 0x9 ] a ` z ) y { f n { h d ) j h g g f } 0xa ^ b c y * z x e m x k g * i k d d e ~ 0xb _ c b x + { y d l y j f + h j e e d  0xc X d e  , | ~ c k ~ m a , o m b b c x 0xd Y e d ~ - }  b j  l ` - n l c c b y 0xe Zfg}.~|ai|oc.mo``az 0xf [gf|/}`h}nb/lnaa`{ 0x10 Dxyc0`bwbq}0sq~~d 0x11 Eyxb1ac~vcp|1rp~e 0x12 Fz{a2b`}u`s2qs||}f 0x13 G{z`3ca|tar~3pr}}|g 0x14 @|}g4df{sfuy4wuzz{` 0x15 A}|f5egzrgtx5vt{{za 0x16 B~e6fdyqdw{6uwxxyb 0x17 C~d7gexpevz7tvyyxc 0x18 Lpqk8hjwjyu8{yvvwl 0x19 Mqpj9ikv~kxt9zxwwvm 0x1a Nrsi:jhu}h{w:y{ttun 0x1b Osrh;kit|izv;xzuuto 0x1c Htuo<lns{n}q<}rrsh 0x1d Iutn=morzo|p=~|ssri 0x1e Jvwm>nlqyls>}ppqj 0x1f Kwvl?ompxm~r?|~qqpk 0x20 t H I S P R O G R A M C A N N O T 0x21 u!I!H!R!!Q!S!N!F!S!@!L!!B!@!O!O!N!U! 0x22 v"J"K"Q""R"P"M"E"P"C"O""A"C"L"L"M"V" 0x23 w#K#J#P##S#Q#L#D#Q#B#N##@#B#M#M#L#W# 0x24 p$L$M$W$$T$V$K$C$V$E$I$$G$E$J$J$K$P$ 0x25 q%M%L%V%%U%W%J%B%W%D%H%%F%D%K%K%J%Q% 0x26 r&N&O&U&&V&T&I&A&T&G&K&&E&G&H&H&I&R& 0x27 s'O'N'T''W'U'H'@'U'F'J''D'F'I'I'H'S' 0x28 |(@(A([((X(Z(G(O(Z(I(E((K(I(F(F(G(\( 0x29 })A)@)Z) )Y)[)F)N)[)H)D) )J)H)G)G)F)]) 0x2a ~*B*C*Y* *Z*X*E*M*X*K*G* *I*K*D*D*E*^* 0x2b +C+B+X+ +[+Y+D+L+Y+J+F+ +H+J+E+E+D+_+ 0x2c x,D,E,_, ,\,^,C,K,^,M,A, ,O,M,B,B,C,X, 0x2d y-E-D-^- -]-_-B-J-_-L-@- -N-L-C-C-B-Y- 0x2e z.F.G.]..^.\.A.I.\.O.C..M.O.@.@.A.Z. 0x2f {/G/F/\//_/]/@/H/]/N/B//L/N/A/A/@/[/ 0x30 d0X0Y0C00@0B0_0W0B0Q0]00S0Q0^0^0_0D0 0x31 e1Y1X1B11A1C1^1V1C1P1\11R1P1_1_1^1E1 0x32 f2Z2[2A22B2@2]2U2@2S2_22Q2S2\2\2]2F2 0x33 g3[3Z3@33C3A3\3T3A3R3^33P3R3]3]3\3G3 0x34 `4\4]4G44D4F4[4S4F4U4Y44W4U4Z4Z4[4@4 0x35 a5]5\5F55E5G5Z5R5G5T5X55V5T5[5[5Z5A5 0x36 b6^6_6E66F6D6Y6Q6D6W6[66U6W6X6X6Y6B6 0x37 c7_7^7D77G7E7X7P7E7V7Z77T7V7Y7Y7X7C7 0x38 l8P8Q8K88H8J8W8_8J8Y8U88[8Y8V8V8W8L8 0x39 m9Q9P9J99I9K9V9^9K9X9T99Z9X9W9W9V9M9 0x3a n:R:S:I::J:H:U:]:H:[:W::Y:[:T:T:U:N: 0x3b o;S;R;H;;K;I;T;\;I;Z;V;;X;Z;U;U;T;O; 0x3c hV>W>M>>N>L>Q>Y>L>_>S>>]>_>P>P>Q>J> 0x3f k?W?V?L??O?M?P?X?M?^?R??\?^?Q?Q?P?K? 0x40 @(@)@3@`@0@2@/@'@2@!@-@`@#@!@.@.@/@4@ 0x41 A)A(A2AaA1A3A.A&A3A A,AaA"A A/A/A.A5A 0x42 B*B+B1BbB2B0B-B%B0B#B/BbB!B#B,B,B-B6B 0x43 C+C*C0CcC3C1C,C$C1C"C.CcC C"C-C-C,C7C 0x44 D,D-D7DdD4D6D+D#D6D%D)DdD'D%D*D*D+D0D 0x45 E-E,E6EeE5E7E*E"E7E$E(EeE&E$E+E+E*E1E 0x46 F.F/F5FfF6F4F)F!F4F'F+FfF%F'F(F(F)F2F 0x47 G/G.G4GgG7G5G(G G5G&G*GgG$G&G)G)G(G3G 0x48 H H!H;HhH8H:H'H/H:H)H%HhH+H)H&H&H'HJ 0x4b K#K"K8KkK;K9K$K,K9K*K&KkK(K*K%K%K$K?K 0x4c L$L%L?LlLL#L+L>L-L!LlL/L-L"L"L#L8L 0x4d M%M$M>MmM=M?M"M*M?M,M MmM.M,M#M#M"M9M 0x4e N&N'N=NnN>NP>P?P$P 0x51 Q9Q8Q"QqQ!Q#Q>Q6Q#Q0QQ%Q 0x52 R:R;R!RrR"R R=R5R R3R?RrR1R3RSsS0S2S=S=SV?V%VvV&V$V9V1V$V7V;VvV5V7V8V8V9V"V 0x57 W?W>W$WwW'W%W8W0W%W6W:WwW4W6W9W9W8W#W 0x58 X0X1X+XxX(X*X7X?X*X9X5XxX;X9X6X6X7X,X 0x59 Y1Y0Y*YyY)Y+Y6Y>Y+Y8Y4YyY:Y8Y7Y7Y6Y-Y 0x5a Z2Z3Z)ZzZ*Z(Z5Z=Z(Z;Z7ZzZ9Z;Z4Z4Z5Z.Z 0x5b [3[2[([{[+[)[4[<[)[:[6[{[8[:[5[5[4[/[ 0x5c \4\5\/\|\,\.\3\;\.\=\1\|\?\=\2\2\3\(\ 0x5d ]5]4].]}]-]/]2]:]/]<]0]}]>]<]3]3]2])] 0x5e ^6^7^-^~^.^,^1^9^,^?^3^~^=^?^0^0^1^*^ 0x5f _7_6_,__/_-_0_8_-_>_2__<_>_1_1_0_+_ 0x60 4`` ``@``````` `@``````` 0x61 5a aaaAaaaaaaa aAaaaaaaa 0x62 6b b bbBbbb bbbbbBbbb b b bb 0x63 7c c ccCccc cccccCccc c c cc 0x64 0d d ddDddd dddd dDddd d d dd 0x65 1e e eeEeee eeeeeEeee e e ee 0x66 2ffffFfff ffff fFfffff ff 0x67 3ggggGggggggg gGggg g ggg 0x68 jjjjJjjjj jj jjJj j jjjjj 0x6b ?kkkkKkkkk kk kkKkk kkkkk 0x6c 8llllLllll ll llLll lllll 0x6d 9mmmmMmmmm mm mmMmm mmmmm 0x6e :nnnnNnnnn nnnnNn nnnnnn 0x6f ;ooooOooooooooOo oooooo 0x70 $ppppPppppppppPppppppp 0x71 %qqqqQqqqqqqqqQqqqqqqq 0x72 &rrrrRrrrrrrrrRrrrrrrr 0x73 'ssssSssssssssSsssssss 0x74 ttttTttttttttTttttttt 0x75 !uuuuUuuuuuuuuUuuuuuuu 0x76 "vvvvVvvvvvvvvVvvvvvvv 0x77 #wwwwWwwwwwwwwWwwwwwww 0x78 ,xxx xXxx xxx xxxXxxxxxx x 0x79 -yyy yYy y yyy yyyYyyyyyy y 0x7a .zzz zZz zzzzzzzZzzzzzzz 0x7b /{{{{[{ { {{{ {{{[{{{{{{{ 0x7c (||||\| |||||||\||||||| 0x7d )}}}}]} }}}}}}}]}}}}}} } 0x7e *~~~ ~^~~ ~~~ ~~~^~~~~~~ ~ 0x7f + _  _  0x80 Ԁ󀠀퀠 0x81 Ձ򁡁쁡 0x82 ւ񂢂 0x83 ׃ 0x84 Є鄤 0x85 х腥 0x86 ҆놦 0x87 Ӈ􇧇ꇧ 0x88 ܈刨 0x89 ݉䉩 0x8a ފ犪 0x8b ߋ拫 0x8c ،ጬ 0x8d ٍ 0x8e ڎ㎮ 0x8f ۏ⏯ 0x90 Đ㐰 0x91 ő⑱ 0x92 ƒᒲ 0x93 Ǔ 0x94 甴 0x95 敵 0x96 –営 0x97 ×䗷 0x98 ̘똸 0x99 ͙ꙹ 0x9a Κ隺 0x9b ϛ蛻 0x9c Ȝ񜼜 0x9d ɝ𝽝 0x9e ʞힾ󞾞 0x9f ˟쟿򟿟 0xa0 ȠɠӠРҠϠǠҠ͠àΠΠϠԠ 0xa1 ɡȡҡѡӡΡơӡ̡¡ϡϡΡա 0xa2 ʢˢѢҢТ͢ŢТâϢâ̢̢֢͢ 0xa3 ˣʣУӣѣ̣ģѣ£Σ£̣ͣͣף 0xa4 ̤ͤפԤ֤ˤä֤ŤɤǤŤʤʤˤФ 0xa5 ̥֥ͥեץʥ¥ץĥȥƥĥ˥˥ʥѥ 0xa6 ΦϦզ֦ԦɦԦǦ˦ŦǦȦȦɦҦ 0xa7 ϧΧԧקէȧէƧʧħƧɧɧȧӧ 0xa8 ۨبڨǨϨڨɨŨ˨ɨƨƨǨܨ 0xa9 ک٩۩ƩΩ۩ȩĩʩȩǩǩƩݩ 0xaa ªê٪ڪتŪͪت˪Ǫɪ˪ĪĪŪު 0xab ë«ث۫٫ī̫٫ʫƫȫʫūūī߫ 0xac ĬŬ߬ܬެìˬެͬϬͬ¬¬ìج 0xad ŭĭޭݭ߭­ʭ̭߭έ̭íí­٭ 0xae ƮǮݮޮܮɮܮϮîͮϮڮ 0xaf ǯƯܯ߯ݯȯݯί¯̯ίۯ 0xb0 ذٰð°߰װ°ѰݰӰѰްް߰İ 0xb1 ٱر±ñޱֱñбܱұб߱߱ޱű 0xb2 ڲ۲²ݲղӲ߲ѲӲܲܲݲƲ 0xb3 ۳ڳóܳԳҳ޳гҳݳݳܳdz 0xb4 ܴݴǴĴƴ۴Ӵƴմٴ״մڴڴ۴ 0xb5 ݵܵƵŵǵڵҵǵԵصֵԵ۵۵ڵ 0xb6 ޶߶ŶƶĶٶѶĶ׶۶ն׶ضضٶ¶ 0xb7 ߷޷ķǷŷطзŷַڷԷַٷٷط÷ 0xb8 иѸ˸ȸʸ׸߸ʸٸո۸ٸָָ׸̸ 0xb9 ѹйʹɹ˹ֹ޹˹عԹڹع׹׹ֹ͹ 0xba ҺӺɺʺȺպݺȺۺ׺ٺۺԺԺպκ 0xbb ӻһȻ˻ɻԻܻɻڻֻػڻջջԻϻ 0xbc Լռϼ̼μӼۼμݼѼ߼ݼҼҼӼȼ 0xbd սԽνͽϽҽڽϽܽн޽ܽӽӽҽɽ 0xbe ־׾;ξ̾Ѿپ̾߾Ӿݾ߾ооѾʾ 0xbf ׿ֿ̿ϿͿпؿͿ޿ҿܿ޿ѿѿп˿ 0xc0 0xc1 0xc2 ª«±²°­¥°£¯¡£¬¬­¶ 0xc3 ëêðóñìäñâîàâííì÷ 0xc4 ĬĭķĴĶīģĶĥĩħĥĪĪīİ 0xc5 ŭŬŶŵŷŪŢŷŤŨŦŤūūŪű 0xc6 ƮƯƵƶƴƩơƴƧƫƥƧƨƨƩƲ 0xc7 ǯǮǴǷǵǨǠǵǦǪǤǦǩǩǨdz 0xc8 ȠȡȻȸȺȧȯȺȩȥȫȩȦȦȧȼ 0xc9 ɡɠɺɹɻɦɮɻɨɤɪɨɧɧɦɽ 0xca ʢʣʹʺʸʥʭʸʫʧʩʫʤʤʥʾ 0xcb ˣˢ˸˻˹ˤˬ˹˪˦˨˪˥˥ˤ˿ 0xcc ̸̡̢̢̤̥̼̣̫̭̯̭̣̿̾̾ 0xcd ͥͤ;ͽͿͪ͢Ϳͬͮͬͣͣ͢͠͹ 0xce ΦΧνξμΡΩμίΣέίΠΠΡκ 0xcf ϧϦϼϿϽϠϨϽϮϢϬϮϡϡϠϻ 0xd0 ийУРТпзТбнгбоопФ 0xd1 ѹѸѢѡѣѾѶѣѰѼѲѰѿѿѾѥ 0xd2 ҺһҡҢҠҽҵҠҳҿұҳҼҼҽҦ 0xd3 ӻӺӠӣӡӼӴӡӲӾӰӲӽӽӼӧ 0xd4 ԼԽԧԤԦԻԳԦԵԹԷԵԺԺԻԠ 0xd5 սռզեէպղէմոնմջջպա 0xd6 ־ֱֵַַָָֹֹֻֿ֥֦֤֤֢ 0xd7 ׿׾פקץ׸װץ׶׺״׶׹׹׸ף 0xd8 ذرثبتطؿتعصػعضضطج 0xd9 ٱٰ٪٩٫ٶپ٫ٸٴٺٸٷٷٶ٭ 0xda ڲڳکڪڨڵڽڨڻڷڹڻڴڴڵڮ 0xdb ۳۲ۨ۫۩۴ۼ۩ۺ۶۸ۺ۵۵۴ۯ 0xdc ܴܵܯܬܮܻܳܮܱܽܿܽܲܲܳܨ 0xdd ݵݴݮݭݯݲݺݯݼݰݾݼݳݳݲݩ 0xde ޶޷ޭޮެޱ޹ެ޿޳޽޿ްްޱު 0xdf ߷߶߬߯߭߰߸߭߾߲߼߾߱߱߰߫ 0xe0 0xe1 0xe2 0xe3 0xe4 0xe5 0xe6 0xe7 0xe8 0xe9 0xea 0xeb 0xec 0xed 0xee 0xef 0xf0 0xf1 0xf2 0xf3 0xf4 0xf5 0xf6 0xf7 0xf8 0xf9 0xfa 0xfb 0xfc 0xfd 0xfe 0xff yara-4.5.3/tests/gcov-summary000077500000000000000000000020271501365277300162120ustar00rootroot00000000000000#!/bin/sh # pseudo code: # - find all .c files in libyara/ # - run gcov --preserve-paths # - fold gcov output into single summary line output # - remember files not executed, and percentages # - at end: output grand total percentage # - at end: output files not executed cd libyara/ find . -type f | egrep "\.c$" | perl -lane ' if (-e $_) { $cmd = qq[gcov --preserve-paths $_]; $out = `$cmd 2>&1`; $out =~ s~(Creating|[^\n]+cannot open notes) [^\n]+\s+~~gs; @out = split(m~\n~, $out); foreach(reverse @out) { if (m~assuming not executed~) { push @assume, $_; next; } if (m~Lines executed:([\d\.]+). of (\d+)~) { $loc_tot += $2; $loc_exe += ($2 * $1 / 100); } printf qq[%-32s%s], $_, m~^Lines~ ? q[] : qq[\n]; } } sub END { if ($loc_tot) { printf qq[Lines executed:%.2f%% of %u total lines in all executed code\n\n], $loc_exe / $loc_tot * 100, $loc_tot; } foreach(@assume) { printf qq[%s\n], $_; } }' exit 0 yara-4.5.3/tests/mapper.c000066400000000000000000000052651501365277300152720ustar00rootroot00000000000000/* Copyright (c) 2021. The YARA Authors. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include char str[] = "!dlrow ,olleH"; int fd; char* map_file(char* path) { if ((fd = open(path, O_RDONLY)) < 0) { fprintf(stderr, "open: %s: %s\n", path, strerror(errno)); exit(1); } char* rv = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (rv == NULL) { fprintf(stderr, "mmap: %s: failed: %s\n", path, strerror(errno)); exit(1); } close(fd); return rv; } int main(int argc, char** argv) { char* buf; if (argc < 2) { fprintf(stderr, "no argument\n"); exit(1); } else if (strcmp(argv[1], "open") == 0) { if (argc < 3) exit(1); printf("%s: %s %s\n", argv[0], argv[1], argv[2]); buf = map_file(argv[2]); } else if (strcmp(argv[1], "patch") == 0) { if (argc < 3) exit(1); printf("%s: %s %s\n", argv[0], argv[1], argv[2]); buf = map_file(argv[2]); for (int i = 0; i < sizeof(str) - 1; i++) { buf[i] = str[sizeof(str) - i - 2]; } } else { fprintf(stderr, "unknown argument <%s>\n", argv[1]); exit(1); } sleep(3600); } yara-4.5.3/tests/oss-fuzz/000077500000000000000000000000001501365277300154325ustar00rootroot00000000000000yara-4.5.3/tests/oss-fuzz/dex_fuzzer.cc000066400000000000000000000014631501365277300201320ustar00rootroot00000000000000#include #include #include YR_RULES* rules = NULL; extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { YR_COMPILER* compiler; if (yr_initialize() != ERROR_SUCCESS) return 0; if (yr_compiler_create(&compiler) != ERROR_SUCCESS) return 0; if (yr_compiler_add_string(compiler, "import \"dex\"", NULL) == 0) yr_compiler_get_rules(compiler, &rules); yr_compiler_destroy(compiler); return 0; } int callback( YR_SCAN_CONTEXT* context, int message, void* message_data, void* user_data) { return CALLBACK_CONTINUE; } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { if (rules == NULL) return 0; yr_rules_scan_mem( rules, data, size, SCAN_FLAGS_NO_TRYCATCH, callback, NULL, 0); return 0; } yara-4.5.3/tests/oss-fuzz/dex_fuzzer_corpus/000077500000000000000000000000001501365277300212125ustar00rootroot000000000000001cf540db2f048bb21bd89379a57279b9ff4c308558715a3baee666a47393d86e000066400000000000000000001025741501365277300316400ustar00rootroot00000000000000yara-4.5.3/tests/oss-fuzz/dex_fuzzer_corpusdex 037Q' Oh bҝLO|pxV4Qpi uX &|k| LLLL#L(L2LVLLLLLLLLLLLLLLM MMMM)MBMbMMMMMM NNPNyNNNNNOO5O8O;O>OAOKOSOWO]OOOOOOOOOOP1PCPpPPP Q8QVQQQQQQQQQQQRRR RRRRR#R(R,RDRcRRRRR S.SIS|SSSS T0T]TTTTU1UlUUUUUVV4VQVkVVVVVW&W?WTWkWWWWWXJXuXX YYYYZZZZ[3[V[u[[[[[[\4\N\e\|\\\\\\]%]:]P]r]]]]]]]^#^:^[^y^^^^^^_#_9_P_h_z________`)`I`h````````````````aa aa+a.a4a8a=aCaHaMaQabawaaaab bb!b&bYbfbpbbbbbbbb,cJcOcucccccccccccddd!d/d8dZdtd|dddddde8eaeeeeeeeeeeeeef ff$f3fDfPf_fgfwf|ffffffffffffgg!g3g:g>gFgQgYgpg}ggggggghhh'h-h4hlHl]ldlnlwllllllllll0m:mNmamlmymmmmmmn8nUnunnnnn3o9oCoToio{ooooooooop ppp"p*p0p5p?pHpQp[pqpvppppppppppqqq$q:qWqwqqqqqqqq rr(r0r;rTrZrjrrrrrrrrrrsss9sEs_srszsssssssssstttt"t1t@t\tltytttttttttu*u7uPucuvuuuuuuuuuuu v0vC/s V?!q A(!1W!2W!]"#h#g$ $ %" &f'Y'i(u(@#)@)&])#d)#)N)@)@!,'-? -m-H-O,.@.m.@/n^/(g/1s0?00?10?R0Y0]0YO0]O1R11j2S12F3R13F4Q14?5P15?6R16Z7<77<77R7R7?17M7M7Y7K7?27h37?;7$M7?N7Z7`7a7.b7m7eo7p7r7-t7%v7L|7_7e7n7e7e7i7i7e7e7e7e7?7?7J7a7Y7?707e7G7@7?7?7a7@ 7B"7G+7?-7?.7??>X1>?>.??1?.=?cO@Y1@e)@eB@.X@.j@.n@e@ @r@s@pAT1A?A;_CU1F?F GV1IW1I?IYOM?M.=N*HO=Q?1Sb1Sc1SSkSn<Sl>Sn?S3SSS2St*Sn/S.>S/HT?1T5T@T.=U?1U6U7U8U.=Vd V %Y:YqY9QZ?ZZ '[Y1[4S\?1\`1\l\l\l\']l]?]l]'^A1_?1`e{`+a?1ala,Wb'0Q71QJxIc2QJIt3QJI4QJI5QJI6I7I҃Ă˂ւ.w i"0pQiwp"Tp[ "[p [ bp0T  wq"@p c"I"Cp06p0eTTn n eTn n0c8nT2 ' T2bq 78n( bq 7( bq 7( 8n' bq 7( 2( T2( ( 2( *2 9> EZ8M;hEIEPWE^MlWMnexbbp0T x>q Ts "^p0n C q 6TtTs"Upn % n e n n e n n S '$;xbbp0Vx"UpPn  n @ n p0T2pRx[ pxn  x[ [ p xNTb !#51DFn0@ n =Td qe n  8("Up9n T n  n qSTd qe n (Ta qhy[ p!y rT qh-y [[Yp9yhTcT3nw Tdn0&C T3TdTDnw n C TcT3ns q EC TcT3T3Rdn C -n HTcT3T3Rdn C -nFTcT3T3Rdn C -n I# =qS(`jy[pry T TT$n Jyy[pyw"Upn Q  n ! n a n qS3TAn QTAqd q f!TAqd TATn  -"4p@]Bn G!TAT$"5p _Bn K!Xq /2TAqd TBqc n 3! qSTAqgTRT%YppyFp$[ Y!\!!\![ [ [ [ "\p[ %"\p[ "1p W [ \! Y!#\!"_p[ y nA 8q m yn? RAYn Bn C#n D# y2"@p n 8'"Upn n e n e n qSn 9!6E5eFn 8 n p lx(T8Tn P 9!%5TFU8T8Tn =Tn n v 8p  8hT8!Tn =Tn n v 8 p  8Tn T8=Tn =5Tn n v 8)p  9p  8'"Upn n v n v n qS)vTn ("Upn n v n v n qSTn (n p h 8"Upn n v  n v n qS(Tn (Cz n< n =Nz1n {# 8 2qSn gz1n { 8 ;qSn vz q kq jz  nw "6p ar r 8r @n n0% 8Tx n 8@ n0# 86RY"UpTyn  n n qSRn 3qSp ( (qN  @n O ?n 8 8'q,  nY("UpTyn  n n qS)jq,  nY((RY"Up n n n n qSRn 36qSp )+2lzBq0 89;n  9.7n  9%6n  9:n  9<n  9 5n  (( { Tn 8{6"@p 2 n@%C 8n ! 8qS qS(GqSM#C{ "@p n I{9nw n n0%2 9 qSTn0#2 "Upn C Tn C n qSk{#nw n n0%! 9 qSTRTr 2 8{Z"@p 2n 8; n@%C "UpGn C n  n qS8n 1 8\S!n 9EqSUS! qS( qS( ); KMJMR{$q "Up4n T n  n qS92( M"{$nw " p Rn Rn 2n0)  r =C({" \p [ tv " Up $n n - n qS  "p l" Up !n n -  n n p l *p l )p l 'p l" Up (n n -  n n p lv 9 U 9 v 9  +p l" \T p r r 8 Sr @n 1 9 r r 8 r @n n n 8 " Up n n n n qS T n =(U 8 tw " \T p r r 8 r @n n0%  8 T8 Tn0& 8 FT8 Bq 8 tRR56TTn 3+" Up >n n n n qS T n }Tn q 9 9 T Tr 8 " Up n n n n qS T n })aRR6TTn 2 TTn 9 " Up Cn n n n qS T n }Tn ( " Up n n n n qS q 9 9 T Tr 8 " Up n n n n qS T n }) T n }" Up )n n n n qS q 9 9 T Tr 8 " Up n n n n qS T n })m q 929 0TTr 8$"Upn n n n qSTn ~' T r r 8 $r @" Up n n n n qS (5MD T" ~P |q 1 "@p n 8X["@Tp qn 8E">"G"Ap  p0 p vn 8lTn n ( e"UpIn Tn n qSnn8 n t 8"@#p n 8 #[("Upn G n n [)z$[)sne( n ();iMKMMA}"@p n 8n ( M} (,q 2CU 8+"Upn C R#n C n qSR#8nu R#q05CqUT8Tn 8 qUq /T.q 2Cnx 9#q. q  q3 r !2qSp qSU!9 " p 1n p 8 p 9p U8nw "p0T%n@*Cenw "7p0 n@*Cx" p0C n C  n C n :OqUpp nr OqU n( n(_'MM }"@%p n 8nw ">"G" Ap ) p0 p n 8dn = n 9n !8)3FF  b n@'( n"Up wn  F  n  n F  n n qS( vJqSnnnv( n ( %F R+MQM~MM$~Mq. q8 r@9A# n-( =~"Upn  U!n  n qSn q .[ $"ap[ T!n q -n T!n q -n pqN Cn M 8p 9q 8pT n 9qSppT $T!n n LT p ~ `~  "@&p rn 8\">"G"Ap ( p0 p tn 8un = n u 9T%n W 9"Upn n W n qST%n W( Cn qS8nT%r r 8;r S"Up+n n W n qSnw n@"W(8nC( ( ( 8n' ( C( (#9_h M]MMMMn: 9n; A3 NqS   "@ 5p "Ap gn 8@n q n  9  qS " Sn  Yn p " Up  n n n qS 8n8n  qS  n(  qS 8n8n( n( 8n8n' n( ( ( e(&?Ypx BbMjEoMMEBn0z Pr0  UqN An MT \dUd8>qN Bn OT n @ !5CFn T 8"UpTen T Fn T n [d(Fn T 8"UpTen T Fn T n [d(F n T 8"UpTen T Fn T n [d("UpTen T Fn T n [d("Upn T Ten T n qS"Upn T Ten T n qS"Upn T Ten T n qS"Upn T Ten T n qSTd8Tdn = qSTd8 Tdn <Td8 Tdn <Td8 Tdn <qS(qS(z3n0z& [b"TbrTb"!r02 =5TbTc"q r0C r 2(  o n -n { n  8DqSn pn|  Hn >pnnt  q n| n? n| n BXn| n@q}q0 8 7n 9n q0 "Up n n x n qS"Up fn nx n n qS8 .n 9nx 8)\Un pnU8Qq 89n 93qSp\8-n 8 HqS(qS -q 2q /(UqS -q 2q /p \ "Up n U n n qSU 8?nu  q04 Y#"Up n R#n  n n qSR#8 nu   q05 q 8n FqSpp(5AM( 8 n| Hn >4JTB"9nTBr R 9<TBr TBr RTB"r q r0 !r0 r"Up n 2 n R n qU X"Ap t <  1 = b9` 1 = 8  1 ;  #en 4 <  n 6 " S p@<}n 9" S p@< n " Up " Sp@=n n n n ;h8Y59 { #en 4 !<29 <  n 9 " S p@